diff --git a/assets/css/dashboard-settings.asset.php b/assets/css/dashboard-settings.asset.php new file mode 100644 index 000000000..ff0ada576 --- /dev/null +++ b/assets/css/dashboard-settings.asset.php @@ -0,0 +1 @@ + array(), 'version' => '4bf9cb210dec800f114a'); diff --git a/assets/css/dashboard-settings.css b/assets/css/dashboard-settings.css new file mode 100644 index 000000000..8477a15c4 --- /dev/null +++ b/assets/css/dashboard-settings.css @@ -0,0 +1 @@ +.fau-settings input[type=text]{max-width:100%;width:500px} diff --git a/assets/css/dashboard-settings.js b/assets/css/dashboard-settings.js new file mode 100644 index 000000000..e69de29bb diff --git a/assets/css/degree-program-list-table.asset.php b/assets/css/degree-program-list-table.asset.php new file mode 100644 index 000000000..e4eb7435a --- /dev/null +++ b/assets/css/degree-program-list-table.asset.php @@ -0,0 +1 @@ + array(), 'version' => '82ff9c0b71a06544dc15'); diff --git a/assets/css/degree-program-list-table.css b/assets/css/degree-program-list-table.css new file mode 100644 index 000000000..8a4b8ce80 --- /dev/null +++ b/assets/css/degree-program-list-table.css @@ -0,0 +1 @@ +.sticky-column{cursor:pointer}.sticky-column span.spinner{float:none;font-size:0;margin:0;opacity:1;visibility:visible} diff --git a/assets/css/degree-program-list-table.js b/assets/css/degree-program-list-table.js new file mode 100644 index 000000000..e69de29bb diff --git a/assets/ts/degree-program-editor.asset.php b/assets/ts/degree-program-editor.asset.php new file mode 100644 index 000000000..7cba14e32 --- /dev/null +++ b/assets/ts/degree-program-editor.asset.php @@ -0,0 +1 @@ + array('lodash', 'react', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-dom-ready', 'wp-editor', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-media-utils', 'wp-rich-text'), 'version' => '4e464280fb25ebc78864'); diff --git a/assets/ts/degree-program-editor.css b/assets/ts/degree-program-editor.css new file mode 100644 index 000000000..ea0c83247 --- /dev/null +++ b/assets/ts/degree-program-editor.css @@ -0,0 +1,5 @@ +.component-multilingual-container .components-tab-panel__tabs-item{height:auto!important;position:relative}.component-multilingual-container .components-tab-panel__tabs-item.is-empty small{color:#717171}.components-base-control__label+.component-multilingual-container{margin-top:-5px} +.entity-selector,.entity-selector .components-form-token-field__input-container,.entity-selector .components-form-token-field__input-container>.components-flex{position:relative}.entity-selector .components-form-token-field__input-container>.components-flex:after{content:"";display:inline-block;font-family:dashicons;font-size:16px;font-style:normal;font-weight:400;line-height:1;position:absolute;right:5px;top:50%;transform:translateY(-50%)}.entity-selector .components-form-token-field__input-container.is-active>.components-flex:after{transform:translateY(-50%) scaleY(-1)}.entity-selector .components-form-token-field__suggestions-list{background:#fff;box-shadow:0 5px 5px 2px rgba(0,0,0,.5);position:absolute;z-index:10}.entity-selector__max-items-notice{background:#fff8ea;border-radius:2px;bottom:-40px;color:#9b7937;margin:0;padding:6px;position:absolute;width:100%;z-index:10}.entity-selector .components-form-token-field__label:empty{display:none} +.block-library-heading-level-dropdown button[aria-label$="1"],.block-library-heading-level-dropdown button[aria-label$="2"],.block-library-heading-level-dropdown button[aria-label$="6"]{display:none}.content-field-blocks-list .block-editor-default-block-appender{display:block!important;height:auto!important}.component-multilingual-container .content-field-blocks-list{padding-top:34px!important}.component-multilingual-container .content-field-blocks-list>.block-list-appender .block-editor-inserter__toggle{display:none!important}.fau-content-field .editor-styles-wrapper{padding-bottom:unset!important} +.c-day-month-picker input:invalid{border-color:red!important;outline-color:red!important} +*{box-sizing:border-box}.wp-block-fau-degree-program-form{--default-font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif}.editor-styles-wrapper .block-editor-block-list__layout.is-root-container>:where(:not(.alignleft):not(.alignright):not(.alignfull)),.editor-styles-wrapper .edit-post-visual-editor__post-title-wrapper>:where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width:none!important}.edit-post-visual-editor__post-title-wrapper{padding-left:var(--wp--style--root--padding-left);padding-right:var(--wp--style--root--padding-right)}.block-editor-block-list__layout .block-editor-block-list__block:not([contenteditable]):focus:after{content:none}.editor-styles-wrapper h5{text-transform:none!important}.editor-post-featured-image__preview img{margin-left:unset}.editor-post-featured-image .components-button+.components-button{display:inline-block}.components-button.block-editor-media-placeholder__cancel-button.is-link{margin-bottom:12px;margin-top:0}.edit-post-visual-editor .components-button.has-icon.components-form-token-field__remove-token{padding:0}@keyframes shine{to{background-position-x:-200%}}.loader-card{animation:shine 1.5s linear infinite;background:#eee;background:linear-gradient(110deg,#ececec 8%,#f5f5f5 18%,#ececec 33%);background-size:200% 100%;overflow:hidden}label[class^=components-][class*=__label],span[class^=components-][class*=__label]{font-size:14px!important;text-transform:none!important}.components-base-control__field,.components-form-token-field__input-container{margin-bottom:0!important} diff --git a/assets/ts/degree-program-editor.js b/assets/ts/degree-program-editor.js new file mode 100644 index 000000000..aa75e9135 --- /dev/null +++ b/assets/ts/degree-program-editor.js @@ -0,0 +1 @@ +(()=>{var e={146:(e,t,r)=>{"use strict";var n=r(404),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},i={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},o={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function c(e){return n.isMemo(e)?o:l[e.$$typeof]||a}l[n.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[n.Memo]=o;var s=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,f=Object.getOwnPropertyDescriptor,m=Object.getPrototypeOf,p=Object.prototype;e.exports=function e(t,r,n){if("string"!=typeof r){if(p){var a=m(r);a&&a!==p&&e(t,a,n)}var o=u(r);d&&(o=o.concat(d(r)));for(var l=c(t),g=c(r),h=0;h{"use strict";var r="function"==typeof Symbol&&Symbol.for,n=r?Symbol.for("react.element"):60103,a=r?Symbol.for("react.portal"):60106,i=r?Symbol.for("react.fragment"):60107,o=r?Symbol.for("react.strict_mode"):60108,l=r?Symbol.for("react.profiler"):60114,c=r?Symbol.for("react.provider"):60109,s=r?Symbol.for("react.context"):60110,u=r?Symbol.for("react.async_mode"):60111,d=r?Symbol.for("react.concurrent_mode"):60111,f=r?Symbol.for("react.forward_ref"):60112,m=r?Symbol.for("react.suspense"):60113,p=r?Symbol.for("react.suspense_list"):60120,g=r?Symbol.for("react.memo"):60115,h=r?Symbol.for("react.lazy"):60116,v=r?Symbol.for("react.block"):60121,b=r?Symbol.for("react.fundamental"):60117,y=r?Symbol.for("react.responder"):60118,_=r?Symbol.for("react.scope"):60119;function k(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case n:switch(e=e.type){case u:case d:case i:case l:case o:case m:return e;default:switch(e=e&&e.$$typeof){case s:case f:case h:case g:case c:return e;default:return t}}case a:return t}}}function E(e){return k(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=s,t.ContextProvider=c,t.Element=n,t.ForwardRef=f,t.Fragment=i,t.Lazy=h,t.Memo=g,t.Portal=a,t.Profiler=l,t.StrictMode=o,t.Suspense=m,t.isAsyncMode=function(e){return E(e)||k(e)===u},t.isConcurrentMode=E,t.isContextConsumer=function(e){return k(e)===s},t.isContextProvider=function(e){return k(e)===c},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===n},t.isForwardRef=function(e){return k(e)===f},t.isFragment=function(e){return k(e)===i},t.isLazy=function(e){return k(e)===h},t.isMemo=function(e){return k(e)===g},t.isPortal=function(e){return k(e)===a},t.isProfiler=function(e){return k(e)===l},t.isStrictMode=function(e){return k(e)===o},t.isSuspense=function(e){return k(e)===m},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===i||e===d||e===l||e===o||e===m||e===p||"object"==typeof e&&null!==e&&(e.$$typeof===h||e.$$typeof===g||e.$$typeof===c||e.$$typeof===s||e.$$typeof===f||e.$$typeof===b||e.$$typeof===y||e.$$typeof===_||e.$$typeof===v)},t.typeOf=k},404:(e,t,r)=>{"use strict";e.exports=r(72)},799:(e,t)=>{"use strict";var r=60103,n=60106,a=60107,i=60108,o=60114,l=60109,c=60110,s=60112,u=60113,d=60120,f=60115,m=60116,p=60121,g=60122,h=60117,v=60129,b=60131;if("function"==typeof Symbol&&Symbol.for){var y=Symbol.for;r=y("react.element"),n=y("react.portal"),a=y("react.fragment"),i=y("react.strict_mode"),o=y("react.profiler"),l=y("react.provider"),c=y("react.context"),s=y("react.forward_ref"),u=y("react.suspense"),d=y("react.suspense_list"),f=y("react.memo"),m=y("react.lazy"),p=y("react.block"),g=y("react.server.block"),h=y("react.fundamental"),v=y("react.debug_trace_mode"),b=y("react.legacy_hidden")}t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===a||e===o||e===v||e===i||e===u||e===d||e===b||"object"==typeof e&&null!==e&&(e.$$typeof===m||e.$$typeof===f||e.$$typeof===l||e.$$typeof===c||e.$$typeof===s||e.$$typeof===h||e.$$typeof===p||e[0]===g)},t.typeOf=function(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case a:case o:case i:case u:case d:return e;default:switch(e=e&&e.$$typeof){case c:case s:case m:case f:case l:return e;default:return t}}case n:return t}}}},363:(e,t,r)=>{"use strict";e.exports=r(799)},833:e=>{e.exports=function(e,t,r,n){var a=r?r.call(n,e,t):void 0;if(void 0!==a)return!!a;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var i=Object.keys(e),o=Object.keys(t);if(i.length!==o.length)return!1;for(var l=Object.prototype.hasOwnProperty.bind(t),c=0;c{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.nc=void 0,(()=>{"use strict";function e(e){for(var t=arguments.length,r=Array(t>1?t-1:0),n=1;n3?t.i-4:t.i:Array.isArray(e)?1:c(e)?2:s(e)?3:0}function o(e,t){return 2===i(e)?e.has(t):Object.prototype.hasOwnProperty.call(e,t)}function l(e,t,r){var n=i(e);2===n?e.set(t,r):3===n?(e.delete(t),e.add(r)):e[t]=r}function c(e){return F&&e instanceof Map}function s(e){return z&&e instanceof Set}function u(e){return e.o||e.t}function d(e){if(Array.isArray(e))return Array.prototype.slice.call(e);var t=U(e);delete t[$];for(var r=W(t),n=0;n1&&(e.set=e.add=e.clear=e.delete=m),Object.freeze(e),r&&a(e,(function(e,t){return f(t,!0)}),!0)),e}function m(){e(2)}function p(e){return null==e||"object"!=typeof e||Object.isFrozen(e)}function g(t){var r=G[t];return r||e(18,t),r}function h(){return q}function v(e,t){t&&(g("Patches"),e.u=[],e.s=[],e.v=t)}function b(e){y(e),e.p.forEach(k),e.p=null}function y(e){e===q&&(q=e.l)}function _(e){return q={p:[],l:q,h:e,m:!0,_:0}}function k(e){var t=e[$];0===t.i||1===t.i?t.j():t.O=!0}function E(t,r){r._=r.p.length;var a=r.p[0],i=void 0!==t&&t!==a;return r.h.g||g("ES5").S(r,t,i),i?(a[$].P&&(b(r),e(4)),n(t)&&(t=x(r,t),r.l||S(r,t)),r.u&&g("Patches").M(a[$].t,t,r.u,r.s)):t=x(r,a,[]),b(r),r.u&&r.v(r.u,r.s),t!==B?t:void 0}function x(e,t,r){if(p(t))return t;var n=t[$];if(!n)return a(t,(function(a,i){return w(e,n,t,a,i,r)}),!0),t;if(n.A!==e)return t;if(!n.P)return S(e,n.t,!0),n.t;if(!n.I){n.I=!0,n.A._--;var i=4===n.i||5===n.i?n.o=d(n.k):n.o;a(3===n.i?new Set(i):i,(function(t,a){return w(e,n,i,t,a,r)})),S(e,i,!1),r&&e.u&&g("Patches").N(n,r,e.u,e.s)}return n.o}function w(e,r,a,i,c,s){if(t(c)){var u=x(e,c,s&&r&&3!==r.i&&!o(r.R,i)?s.concat(i):void 0);if(l(a,i,u),!t(u))return;e.m=!1}if(n(c)&&!p(c)){if(!e.h.D&&e._<1)return;x(e,c),r&&r.A.l||S(e,c)}}function S(e,t,r){void 0===r&&(r=!1),e.h.D&&e.m&&f(t,r)}function C(e,t){var r=e[$];return(r?u(r):e)[t]}function A(e,t){if(t in e)for(var r=Object.getPrototypeOf(e);r;){var n=Object.getOwnPropertyDescriptor(r,t);if(n)return n;r=Object.getPrototypeOf(r)}}function P(e){e.P||(e.P=!0,e.l&&P(e.l))}function O(e){e.o||(e.o=d(e.t))}function R(e,t,r){var n=c(t)?g("MapSet").F(t,r):s(t)?g("MapSet").T(t,r):e.g?function(e,t){var r=Array.isArray(e),n={i:r?1:0,A:t?t.A:h(),P:!1,I:!1,R:{},l:t,t:e,k:null,o:null,j:null,C:!1},a=n,i=V;r&&(a=[n],i=Y);var o=Proxy.revocable(a,i),l=o.revoke,c=o.proxy;return n.k=c,n.j=l,c}(t,r):g("ES5").J(t,r);return(r?r.A:h()).p.push(n),n}function T(r){return t(r)||e(22,r),function e(t){if(!n(t))return t;var r,o=t[$],c=i(t);if(o){if(!o.P&&(o.i<4||!g("ES5").K(o)))return o.t;o.I=!0,r=j(t,c),o.I=!1}else r=j(t,c);return a(r,(function(t,n){o&&function(e,t){return 2===i(e)?e.get(t):e[t]}(o.t,t)===n||l(r,t,e(n))})),3===c?new Set(r):r}(r)}function j(e,t){switch(t){case 2:return new Map(e);case 3:return Array.from(e)}return d(e)}var I,q,D="undefined"!=typeof Symbol&&"symbol"==typeof Symbol("x"),F="undefined"!=typeof Map,z="undefined"!=typeof Set,M="undefined"!=typeof Proxy&&void 0!==Proxy.revocable&&"undefined"!=typeof Reflect,B=D?Symbol.for("immer-nothing"):((I={})["immer-nothing"]=!0,I),N=D?Symbol.for("immer-draftable"):"__$immer_draftable",$=D?Symbol.for("immer-state"):"__$immer_state",L="undefined"!=typeof Symbol&&Symbol.iterator||"@@iterator",H=""+Object.prototype.constructor,W="undefined"!=typeof Reflect&&Reflect.ownKeys?Reflect.ownKeys:void 0!==Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:Object.getOwnPropertyNames,U=Object.getOwnPropertyDescriptors||function(e){var t={};return W(e).forEach((function(r){t[r]=Object.getOwnPropertyDescriptor(e,r)})),t},G={},V={get:function(e,t){if(t===$)return e;var r=u(e);if(!o(r,t))return function(e,t,r){var n,a=A(t,r);return a?"value"in a?a.value:null===(n=a.get)||void 0===n?void 0:n.call(e.k):void 0}(e,r,t);var a=r[t];return e.I||!n(a)?a:a===C(e.t,t)?(O(e),e.o[t]=R(e.A.h,a,e)):a},has:function(e,t){return t in u(e)},ownKeys:function(e){return Reflect.ownKeys(u(e))},set:function(e,t,r){var n=A(u(e),t);if(null==n?void 0:n.set)return n.set.call(e.k,r),!0;if(!e.P){var a=C(u(e),t),i=null==a?void 0:a[$];if(i&&i.t===r)return e.o[t]=r,e.R[t]=!1,!0;if(function(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t}(r,a)&&(void 0!==r||o(e.t,t)))return!0;O(e),P(e)}return e.o[t]===r&&(void 0!==r||t in e.o)||Number.isNaN(r)&&Number.isNaN(e.o[t])||(e.o[t]=r,e.R[t]=!0),!0},deleteProperty:function(e,t){return void 0!==C(e.t,t)||t in e.t?(e.R[t]=!1,O(e),P(e)):delete e.R[t],e.o&&delete e.o[t],!0},getOwnPropertyDescriptor:function(e,t){var r=u(e),n=Reflect.getOwnPropertyDescriptor(r,t);return n?{writable:!0,configurable:1!==e.i||"length"!==t,enumerable:n.enumerable,value:r[t]}:n},defineProperty:function(){e(11)},getPrototypeOf:function(e){return Object.getPrototypeOf(e.t)},setPrototypeOf:function(){e(12)}},Y={};a(V,(function(e,t){Y[e]=function(){return arguments[0]=arguments[0][0],t.apply(this,arguments)}})),Y.deleteProperty=function(e,t){return Y.set.call(this,e,t,void 0)},Y.set=function(e,t,r){return V.set.call(this,e[0],t,r,e[0])};var K=function(){function r(t){var r=this;this.g=M,this.D=!0,this.produce=function(t,a,i){if("function"==typeof t&&"function"!=typeof a){var o=a;a=t;var l=r;return function(e){var t=this;void 0===e&&(e=o);for(var r=arguments.length,n=Array(r>1?r-1:0),i=1;i1?n-1:0),i=1;i=0;n--){var a=r[n];if(0===a.path.length&&"replace"===a.op){e=a.value;break}}n>-1&&(r=r.slice(n+1));var i=g("Patches").$;return t(e)?i(e,r):this.produce(e,(function(e){return i(e,r)}))},r}(),X=new K,J=X.produce;X.produceWithPatches.bind(X),X.setAutoFreeze.bind(X),X.setUseProxies.bind(X),X.applyPatches.bind(X),X.createDraft.bind(X),X.finishDraft.bind(X);const Z=J;!function(){function t(e,t){function r(){this.constructor=e}l(e,t),e.prototype=(r.prototype=t.prototype,new r)}function r(e){e.o||(e.R=new Map,e.o=new Map(e.t))}function i(e){e.o||(e.o=new Set,e.t.forEach((function(t){if(n(t)){var r=R(e.A.h,t,e);e.p.set(t,r),e.o.add(r)}else e.o.add(t)})))}function o(t){t.O&&e(3,JSON.stringify(u(t)))}var l=function(e,t){return(l=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])})(e,t)},c=function(){function e(e,t){return this[$]={i:2,l:t,A:t?t.A:h(),P:!1,I:!1,o:void 0,R:void 0,t:e,k:this,C:!1,O:!1},this}t(e,Map);var i=e.prototype;return Object.defineProperty(i,"size",{get:function(){return u(this[$]).size}}),i.has=function(e){return u(this[$]).has(e)},i.set=function(e,t){var n=this[$];return o(n),u(n).has(e)&&u(n).get(e)===t||(r(n),P(n),n.R.set(e,!0),n.o.set(e,t),n.R.set(e,!0)),this},i.delete=function(e){if(!this.has(e))return!1;var t=this[$];return o(t),r(t),P(t),t.t.has(e)?t.R.set(e,!1):t.R.delete(e),t.o.delete(e),!0},i.clear=function(){var e=this[$];o(e),u(e).size&&(r(e),P(e),e.R=new Map,a(e.t,(function(t){e.R.set(t,!1)})),e.o.clear())},i.forEach=function(e,t){var r=this;u(this[$]).forEach((function(n,a){e.call(t,r.get(a),a,r)}))},i.get=function(e){var t=this[$];o(t);var a=u(t).get(e);if(t.I||!n(a))return a;if(a!==t.t.get(e))return a;var i=R(t.A.h,a,t);return r(t),t.o.set(e,i),i},i.keys=function(){return u(this[$]).keys()},i.values=function(){var e,t=this,r=this.keys();return(e={})[L]=function(){return t.values()},e.next=function(){var e=r.next();return e.done?e:{done:!1,value:t.get(e.value)}},e},i.entries=function(){var e,t=this,r=this.keys();return(e={})[L]=function(){return t.entries()},e.next=function(){var e=r.next();if(e.done)return e;var n=t.get(e.value);return{done:!1,value:[e.value,n]}},e},i[L]=function(){return this.entries()},e}(),s=function(){function e(e,t){return this[$]={i:3,l:t,A:t?t.A:h(),P:!1,I:!1,o:void 0,t:e,k:this,p:new Map,O:!1,C:!1},this}t(e,Set);var r=e.prototype;return Object.defineProperty(r,"size",{get:function(){return u(this[$]).size}}),r.has=function(e){var t=this[$];return o(t),t.o?!!t.o.has(e)||!(!t.p.has(e)||!t.o.has(t.p.get(e))):t.t.has(e)},r.add=function(e){var t=this[$];return o(t),this.has(e)||(i(t),P(t),t.o.add(e)),this},r.delete=function(e){if(!this.has(e))return!1;var t=this[$];return o(t),i(t),P(t),t.o.delete(e)||!!t.p.has(e)&&t.o.delete(t.p.get(e))},r.clear=function(){var e=this[$];o(e),u(e).size&&(i(e),P(e),e.o.clear())},r.values=function(){var e=this[$];return o(e),i(e),e.o.values()},r.entries=function(){var e=this[$];return o(e),i(e),e.o.entries()},r.keys=function(){return this.values()},r[L]=function(){return this.values()},r.forEach=function(e,t){for(var r=this.values(),n=r.next();!n.done;)e.call(t,n.value,n.value,this),n=r.next()},e}();!function(e,t){G[e]||(G[e]=t)}("MapSet",{F:function(e,t){return new c(e,t)},T:function(e,t){return new s(e,t)}})}();var Q=function(){return Q=Object.assign||function(e){for(var t,r=1,n=arguments.length;r0)&&!(n=i.next()).done;)o.push(n.value)}catch(e){a={error:e}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(a)throw a.error}}return o}function re(e,t,r){if(r||2===arguments.length)for(var n,a=0,i=t.length;a0}),[u]);return(0,fe.subscribe)((function(){var e=(0,fe.select)(me.store),t=e.isSavingPost,r=e.isAutosavingPost;l(t()&&!r())})),(0,oe.useEffect)((function(){if(!o&&c){var e=(0,fe.select)(de.store).getLastEntitySaveError("postType",pe().postType,c);e?(s({status:"draft"},{undoIgnore:!0}),a(new Map(re([],te(function(e){var t,r=new Map;if("rest_invalid_param"!==e.code)return r;var n=null===(t=e.data)||void 0===t?void 0:t.params;return void 0===n||Object.entries(n).forEach((function(e){var t={errorCode:e[1].code||"",message:e[1].message};r.set(e[0],Q(Q({},t),{message:ve(e[0],t)}))})),r}(e)),!1)))):a(new Map)}}),[o,c,s]),le().createElement(be.Provider,{value:{errors:n,getFieldErrors:u,removeError:function(e){a((function(t){var r=new Map(t);return r.delete(e),r.delete("".concat(e,".id")),r}))},fieldHasErrors:d}},t)};var ke=(0,oe.createContext)({}),Ee=function(){return(0,oe.useContext)(ke)};const xe=function(e){var t=e.children,r=te((0,de.useEntityProp)("postType",pe().postType,pe().propertyName),2),n=r[0],a=r[1],i=ye().removeError,o=(0,fe.useDispatch)(me.store).editPost,l=(0,oe.useCallback)((function(e,t){"title.de"===e&&"string"==typeof t&&o({excerpt:t})}),[o]),c=(0,oe.useCallback)((function(e,t){i(e),a(Z(n,(function(r){return(0,ue.set)(r,e,t)}))),l(e,t)}),[a,n,i,l]);return le().createElement(ke.Provider,{value:{handleChange:c,values:n}},t)},we=function(e){var t=e.children;return le().createElement(_e,null,le().createElement(xe,null,t))},Se=window.wp.components,Ce=function(e){var t=e.tabs;return le().createElement(Se.TabPanel,{tabs:t},(function(e){return le().createElement(le().Fragment,null,e.component)}))};var Ae=r(363),Pe=r(833),Oe=r.n(Pe);const Re=function(e){function t(e,n,c,s,f){for(var m,p,g,h,_,E=0,x=0,w=0,S=0,C=0,j=0,q=g=m=0,F=0,z=0,M=0,B=0,N=c.length,$=N-1,L="",H="",W="",U="";Fm)&&(B=(L=L.replace(" ",":")).length),0n&&(n=(t=t.trim()).charCodeAt(0)),n){case 38:return t.replace(h,"$1"+e.trim());case 58:return e.trim()+t.replace(h,"$1"+e.trim());default:if(0<1*r&&0c.charCodeAt(8))break;case 115:o=o.replace(c,"-webkit-"+c)+";"+o;break;case 207:case 102:o=o.replace(c,"-webkit-"+(102n.charCodeAt(0)&&(n=n.trim()),n=[n],01?t-1:0),n=1;n0?" Args: "+r.join(", "):""))}var Ke=function(){function e(e){this.groupSizes=new Uint32Array(512),this.length=512,this.tag=e}var t=e.prototype;return t.indexOfGroup=function(e){for(var t=0,r=0;r=this.groupSizes.length){for(var r=this.groupSizes,n=r.length,a=n;e>=a;)(a<<=1)<0&&Ye(16,""+e);this.groupSizes=new Uint32Array(a),this.groupSizes.set(r),this.length=a;for(var i=n;i=this.length||0===this.groupSizes[e])return t;for(var r=this.groupSizes[e],n=this.indexOfGroup(e),a=n+r,i=n;i=Ze&&(Ze=t+1),Xe.set(e,t),Je.set(t,e)},rt="style["+Ue+'][data-styled-version="5.3.6"]',nt=new RegExp("^"+Ue+'\\.g(\\d+)\\[id="([\\w\\d-]+)"\\].*?"([^"]*)'),at=function(e,t,r){for(var n,a=r.split(","),i=0,o=a.length;i=0;r--){var n=t[r];if(n&&1===n.nodeType&&n.hasAttribute(Ue))return n}}(r),i=void 0!==a?a.nextSibling:null;n.setAttribute(Ue,"active"),n.setAttribute("data-styled-version","5.3.6");var o=ot();return o&&n.setAttribute("nonce",o),r.insertBefore(n,i),n},ct=function(){function e(e){var t=this.element=lt(e);t.appendChild(document.createTextNode("")),this.sheet=function(e){if(e.sheet)return e.sheet;for(var t=document.styleSheets,r=0,n=t.length;r=0){var r=document.createTextNode(t),n=this.nodes[e];return this.element.insertBefore(r,n||null),this.length++,!0}return!1},t.deleteRule=function(e){this.element.removeChild(this.nodes[e]),this.length--},t.getRule=function(e){return e0&&(s+=e+",")})),n+=""+l+c+'{content:"'+s+'"}/*!sc*/\n'}}}return n}(this)},e}(),pt=/(a)(d)/gi,gt=function(e){return String.fromCharCode(e+(e>25?39:97))};function ht(e){var t,r="";for(t=Math.abs(e);t>52;t=t/52|0)r=gt(t%52)+r;return(gt(t%52)+r).replace(pt,"$1-$2")}var vt=function(e,t){for(var r=t.length;r;)e=33*e^t.charCodeAt(--r);return e},bt=function(e){return vt(5381,e)};function yt(e){for(var t=0;t>>0);if(!t.hasNameForId(n,o)){var l=r(i,"."+o,void 0,n);t.insertRules(n,o,l)}a.push(o),this.staticRulesId=o}else{for(var c=this.rules.length,s=vt(this.baseHash,r.hash),u="",d=0;d>>0);if(!t.hasNameForId(n,g)){var h=r(u,"."+g,void 0,n);t.insertRules(n,g,h)}a.push(g)}}return a.join(" ")},e}(),Et=/^\s*\/\/.*$/gm,xt=[":","[",".","#"];function wt(e){var t,r,n,a,i=void 0===e?$e:e,o=i.options,l=void 0===o?$e:o,c=i.plugins,s=void 0===c?Ne:c,u=new Re(l),d=[],f=function(e){function t(t){if(t)try{e(t+"}")}catch(e){}}return function(r,n,a,i,o,l,c,s,u,d){switch(r){case 1:if(0===u&&64===n.charCodeAt(0))return e(n+";"),"";break;case 2:if(0===s)return n+"/*|*/";break;case 3:switch(s){case 102:case 112:return e(a[0]+n),"";default:return n+(0===d?"/*|*/":"")}case-2:n.split("/*|*/}").forEach(t)}}}((function(e){d.push(e)})),m=function(e,n,i){return 0===n&&-1!==xt.indexOf(i[r.length])||i.match(a)?e:"."+t};function p(e,i,o,l){void 0===l&&(l="&");var c=e.replace(Et,""),s=i&&o?o+" "+i+" { "+c+" }":c;return t=l,r=i,n=new RegExp("\\"+r+"\\b","g"),a=new RegExp("(\\"+r+"\\b){2,}"),u(o||!i?"":i,s)}return u.use([].concat(s,[function(e,t,a){2===e&&a.length&&a[0].lastIndexOf(r)>0&&(a[0]=a[0].replace(n,m))},f,function(e){if(-2===e){var t=d;return d=[],t}}])),p.hash=s.length?s.reduce((function(e,t){return t.name||Ye(15),vt(e,t.name)}),5381).toString():"",p}var St=le().createContext(),Ct=(St.Consumer,le().createContext()),At=(Ct.Consumer,new mt),Pt=wt();function Ot(){return(0,oe.useContext)(St)||At}function Rt(e){var t=(0,oe.useState)(e.stylisPlugins),r=t[0],n=t[1],a=Ot(),i=(0,oe.useMemo)((function(){var t=a;return e.sheet?t=e.sheet:e.target&&(t=t.reconstructWithOptions({target:e.target},!1)),e.disableCSSOMInjection&&(t=t.reconstructWithOptions({useCSSOMInjection:!1})),t}),[e.disableCSSOMInjection,e.sheet,e.target]),o=(0,oe.useMemo)((function(){return wt({options:{prefix:!e.disableVendorPrefixes},plugins:r})}),[e.disableVendorPrefixes,r]);return(0,oe.useEffect)((function(){Oe()(r,e.stylisPlugins)||n(e.stylisPlugins)}),[e.stylisPlugins]),le().createElement(St.Provider,{value:i},le().createElement(Ct.Provider,{value:o},e.children))}var Tt=function(){function e(e,t){var r=this;this.inject=function(e,t){void 0===t&&(t=Pt);var n=r.name+t.hash;e.hasNameForId(r.id,n)||e.insertRules(r.id,n,t(r.rules,n,"@keyframes"))},this.toString=function(){return Ye(12,String(r.name))},this.name=e,this.id="sc-keyframes-"+e,this.rules=t}return e.prototype.getName=function(e){return void 0===e&&(e=Pt),this.name+e.hash},e}(),jt=/([A-Z])/,It=/([A-Z])/g,qt=/^ms-/,Dt=function(e){return"-"+e.toLowerCase()};function Ft(e){return jt.test(e)?e.replace(It,Dt).replace(qt,"-ms-"):e}var zt=function(e){return null==e||!1===e||""===e};function Mt(e,t,r,n){if(Array.isArray(e)){for(var a,i=[],o=0,l=e.length;o1?t-1:0),n=1;n?@[\\\]^`{|}~-]+/g,Lt=/(^-|-$)/g;function Ht(e){return e.replace($t,"-").replace(Lt,"")}function Wt(e){return"string"==typeof e&&!0}var Ut=function(e){return"function"==typeof e||"object"==typeof e&&null!==e&&!Array.isArray(e)},Gt=function(e){return"__proto__"!==e&&"constructor"!==e&&"prototype"!==e};function Vt(e,t,r){var n=e[r];Ut(t)&&Ut(n)?Yt(n,t):e[r]=t}function Yt(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n>>0)}("5.3.6"+r+Xt[r]);return t?t+"-"+n:n}(t.displayName,t.parentComponentId):l,s=t.displayName,u=void 0===s?function(e){return Wt(e)?"styled."+e:"Styled("+He(e)+")"}(e):s,d=t.displayName&&t.componentId?Ht(t.displayName)+"-"+t.componentId:t.componentId||c,f=n&&e.attrs?Array.prototype.concat(e.attrs,o).filter(Boolean):o,m=t.shouldForwardProp;n&&e.shouldForwardProp&&(m=t.shouldForwardProp?function(r,n,a){return e.shouldForwardProp(r,n,a)&&t.shouldForwardProp(r,n,a)}:e.shouldForwardProp);var p,g=new kt(r,d,n?e.componentStyle:void 0),h=g.isStatic&&0===o.length,v=function(e,t){return function(e,t,r,n){var a=e.attrs,i=e.componentStyle,o=e.defaultProps,l=e.foldedComponentIds,c=e.shouldForwardProp,s=e.styledComponentId,u=e.target,d=function(e,t,r){void 0===e&&(e=$e);var n=ze({},t,{theme:e}),a={};return r.forEach((function(e){var t,r,i,o=e;for(t in Le(o)&&(o=o(n)),o)n[t]=a[t]="className"===t?(r=a[t],i=o[t],r&&i?r+" "+i:r||i):o[t]})),[n,a]}(function(e,t,r){return void 0===r&&(r=$e),e.theme!==r.theme&&e.theme||t||r.theme}(t,(0,oe.useContext)(Kt),o)||$e,t,a),f=d[0],m=d[1],p=function(e,t,r,n){var a=Ot(),i=(0,oe.useContext)(Ct)||Pt;return t?e.generateAndInjectStyles($e,a,i):e.generateAndInjectStyles(r,a,i)}(i,n,f),g=r,h=m.$as||t.$as||m.as||t.as||u,v=Wt(h),b=m!==t?ze({},t,{},m):t,y={};for(var _ in b)"$"!==_[0]&&"as"!==_&&("forwardedAs"===_?y.as=b[_]:(c?c(_,qe,h):!v||qe(_))&&(y[_]=b[_]));return t.style&&m.style!==t.style&&(y.style=ze({},t.style,{},m.style)),y.className=Array.prototype.concat(l,s,p!==s?p:null,t.className,m.className).filter(Boolean).join(" "),y.ref=g,(0,oe.createElement)(h,y)}(p,e,t,h)};return v.displayName=u,(p=le().forwardRef(v)).attrs=f,p.componentStyle=g,p.displayName=u,p.shouldForwardProp=m,p.foldedComponentIds=n?Array.prototype.concat(e.foldedComponentIds,e.styledComponentId):Ne,p.styledComponentId=d,p.target=n?e.target:e,p.withComponent=function(e){var n=t.componentId,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n=0||(a[r]=e[r]);return a}(t,["componentId"]),i=n&&n+"-"+(Wt(e)?e:Ht(He(e)));return Jt(e,ze({},a,{attrs:f,componentId:i}),r)},Object.defineProperty(p,"defaultProps",{get:function(){return this._foldedDefaultProps},set:function(t){this._foldedDefaultProps=n?Yt({},e.defaultProps,t):t}}),p.toString=function(){return"."+p.styledComponentId},a&&Fe()(p,e,{attrs:!0,componentStyle:!0,displayName:!0,foldedComponentIds:!0,shouldForwardProp:!0,styledComponentId:!0,target:!0,withComponent:!0}),p}var Zt=function(e){return function e(t,r,n){if(void 0===n&&(n=$e),!(0,Ae.isValidElementType)(r))return Ye(1,String(r));var a=function(){return t(r,n,Nt.apply(void 0,arguments))};return a.withConfig=function(a){return e(t,r,ze({},n,{},a))},a.attrs=function(a){return e(t,r,ze({},n,{attrs:Array.prototype.concat(n.attrs,a).filter(Boolean)}))},a}(Jt,e)};["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link","main","map","mark","marquee","menu","menuitem","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","picture","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","circle","clipPath","defs","ellipse","foreignObject","g","image","line","linearGradient","marker","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","svg","text","textPath","tspan"].forEach((function(e){Zt[e]=Zt(e)})),function(){var e=function(e,t){this.rules=e,this.componentId=t,this.isStatic=yt(e),mt.registerId(this.componentId+1)}.prototype;e.createStyles=function(e,t,r,n){var a=n(Mt(this.rules,t,r,n).join(""),""),i=this.componentId+e;r.insertRules(i,i,a)},e.removeStyles=function(e,t){t.clearRules(this.componentId+e)},e.renderStyles=function(e,t,r,n){e>2&&mt.registerId(this.componentId+e),this.removeStyles(e,r),this.createStyles(e,t,r,n)}}(),function(){var e=function(){var e=this;this._emitSheetCSS=function(){var t=e.instance.toString();if(!t)return"";var r=ot();return""},this.getStyleTags=function(){return e.sealed?Ye(2):e._emitSheetCSS()},this.getStyleElement=function(){var t;if(e.sealed)return Ye(2);var r=((t={})[Ue]="",t["data-styled-version"]="5.3.6",t.dangerouslySetInnerHTML={__html:e.instance.toString()},t),n=ot();return n&&(r.nonce=n),[le().createElement("style",ze({},r,{key:"sc-0-0"}))]},this.seal=function(){e.sealed=!0},this.instance=new mt({isServer:!0}),this.sealed=!1}.prototype;e.collectStyles=function(e){return this.sealed?Ye(2):le().createElement(Rt,{sheet:this.instance},e)},e.interleaveWithNodeStream=function(e){return Ye(3)}}();const Qt=Zt;var er=Qt.span(ar||(ar=ne(["\n\tdisplay: block;\n"],["\n\tdisplay: block;\n"]))),tr=Qt.p(ir||(ir=ne(["\n\tmargin: 0;\n\tmargin-top: 4px;\n\tfont-size: 12px;\n\tfont-style: normal;\n\tfont-weight: normal;\n\tcolor: rgb( 117, 117, 117 );\n"],["\n\tmargin: 0;\n\tmargin-top: 4px;\n\tfont-size: 12px;\n\tfont-style: normal;\n\tfont-weight: normal;\n\tcolor: rgb( 117, 117, 117 );\n"]))),rr=function(e){var t=e.label,r=e.help;return le().createElement(le().Fragment,null,le().createElement(er,null,t),!!r&&le().createElement(tr,null,r))};rr.defaultProps={help:void 0};const nr=rr;var ar,ir,or,lr,cr="15px",sr=Qt(Se.FlexItem)(or||(or=ne(["\n\tpadding-left: ",";\n\tpadding-right: ",";\n\tmargin-bottom: ",";\n\n\t","\n\n\t","\n\n\t","\n"],["\n\tpadding-left: ",";\n\tpadding-right: ",";\n\tmargin-bottom: ",";\n\n\t","\n\n\t","\n\n\t","\n"])),cr,cr,"15px",(function(e){return"full"===e.fill&&"\n\t\twidth: 100%;\n\t\tflex: 0 0 100%;\n\t"}),(function(e){return"half"===e.fill&&"\n\t\twidth: 50%;\n\t\tflex: 0 0 50%;\n\t"}),(function(e){return"third"===e.fill&&"\n\t\twidth: 33.333333333%;\n\t\tflex: 0 0 33.333333333%;\n\t"})),ur=Qt(Se.Flex)(lr||(lr=ne(["\n\tmargin: 0 -",";\n"],["\n\tmargin: 0 -",";\n"])),cr);const dr=function(e){var t=e.children,r=e.fill,n=void 0===r?"full":r,a=ee(e,["children","fill"]);return le().createElement(sr,Q({isBlock:"auto"===n||void 0,fill:n},a),t)};let fr=(e=21)=>crypto.getRandomValues(new Uint8Array(e)).reduce(((e,t)=>e+((t&=63)<36?t.toString(36):t<62?(t-26).toString(36).toUpperCase():t>62?"-":"_")),"");var mr=Qt.p(gr||(gr=ne(["\n\tcolor: #cc1818;\n\tfont-size: 12px;\n\tmargin: 5px 0 0;\n\tfont-family: var( --default-font );\n"],["\n\tcolor: #cc1818;\n\tfont-size: 12px;\n\tmargin: 5px 0 0;\n\tfont-family: var( --default-font );\n"])));const pr=function(e){var t=e.errors;return t.size?le().createElement(le().Fragment,null,Array.from(t).map((function(e){var t=te(e,2)[1];return le().createElement(mr,{key:fr()},t.message)}))):null};var gr,hr=(0,oe.createContext)({required:!1}),vr=function(){return(0,oe.useContext)(hr)};const br=function(e){var t=e.name,r=e.fill,n=e.children,a=e.label,i=e.help,o=e.wrapBaseControl,l=void 0===o||o,c=e.displayError,s=void 0===c||c,u=e.required,d=void 0!==u&&u,f=ee(e,["name","fill","children","label","help","wrapBaseControl","displayError","required"]),m=ye().getFieldErrors,p=d?a:"".concat(a," ").concat((0,se._x)("(optional)","backoffice: degree program edit form","fau-degree-program"));return le().createElement(dr,Q({fill:r},f),le().createElement(hr.Provider,{value:{required:d}},l?le().createElement(Se.BaseControl,{label:le().createElement(nr,{label:p,help:i})},n):le().createElement(le().Fragment,null,n)),s&&le().createElement(pr,{errors:m(t)}))},yr=function(e){var t=e.children,r=ee(e,["children"]);return le().createElement(ur,Q({wrap:!0,gap:0,align:"flex-start"},r),t)},_r=window.wp.compose;function kr(e){var t=e.label,r=void 0===t?"":t,n=e.messages,a=e.maxLength,i=e.onChange,o=e.entityToToken,l=e.maxSuggestions,c=e.entities,s=e.searchedEntities,u=e.setSearch,d=e.childOnly,f=te((0,oe.useState)(!1),2),m=f[0],p=f[1],g=te((0,oe.useState)([]),2),h=g[0],v=g[1],b=(0,oe.useRef)(null),y=(0,_r.useDebounce)(u,500);(0,oe.useEffect)((function(){if(c.length>0){var e=c.map(o);v(e)}}),[c,o]);var _=(0,oe.useMemo)((function(){if(a&&h.length>=a)return[];var e=[];return s.filter((function(e){return!(null==e?void 0:e.parent)})).forEach((function(t){var r=s.filter((function(e){return e.parent===t.id}));e=re(re(re([],te(e),!1),[t],!1),te(r),!1)})),e.map(o)}),[s,h,o,a]);return(0,oe.useEffect)((function(){if(b.current&&m){var e=b.current.querySelector(".components-form-token-field__suggestions-list");e&&(e.tabIndex=-1)}}),[m]),le().createElement("div",{className:"entity-selector",ref:b},le().createElement("div",{tabIndex:-1,onFocus:function(){return p(!0)},onBlur:function(){return p(!1)},role:"listbox","aria-required":vr().required},le().createElement(Se.FormTokenField,{label:r,messages:n,maxLength:a,value:h,suggestions:_,onChange:function(e){var t=re(re([],te(c),!1),te(s),!1),r=(0,ue.uniq)(e);v(r);var n=r.map((function(e){return(0,ue.find)(t,(function(t){return o(t)===e}))}));i(n),u("")},onInputChange:y,onFocus:function(){return p(!0)},maxSuggestions:l,__experimentalShowHowTo:!1,__experimentalValidateInput:function(e){var t=re(re([],te(c),!1),te(s),!1),r=(0,ue.find)(t,(function(t){return o(t)===e}));return d?r&&(null==r?void 0:r.parent):r},__experimentalExpandOnFocus:!0})),m&&a&&h.length>=a&&le().createElement("p",{className:"entity-selector__max-items-notice"},(0,se.sprintf)((0,se._nx)("You can only select %d item","You can only select %d items",a,"backoffice: selector message","fau-degree-program"),a)))}function Er(e,t,r){void 0===r&&(r="");var n=[e,t];return r&&n.push(r),n.join(":")}function xr(e){var t;return parseInt(null!==(t=e.split(":")[1])&&void 0!==t?t:0,10)}const wr=(0,fe.withSelect)((function(e,t){var r;if((0,ue.isEmpty)(t.value))return{entities:[]};var n=e(de.store.name).getEntityRecords,a=((0,ue.isArray)(t.value)?t.value:[t.value]).map(xr),i=Q({per_page:-1,orderby:"include",context:"view"},{include:a.join(",")});return{entities:null!==(r=n("taxonomy",pe().taxonomySlugs[t.taxonomy],i))&&void 0!==r?r:[]}})),Sr=(0,fe.withSelect)((function(e,t){var r=te((0,oe.useState)(""),2),n=r[0],a=r[1],i=(0,e(de.store.name).getEntityRecords)("taxonomy",pe().taxonomySlugs[t.taxonomy],Q({per_page:t.maxSuggestions,orderby:"name",order:"asc",context:"view"},{search:n}));return{searchedEntities:null!=i?i:[],setSearch:a}})),Cr=window.wp.htmlEntities,Ar=(0,_r.createHigherOrderComponent)((function(e){return function(t){var r=t.id,n=t.help,a=ee(t,["id","help"]);return le().createElement(Se.BaseControl,{id:r,help:null!=n?n:""},le().createElement(e,Q({entityToToken:function(e){return e.parent?"--- ".concat((0,Cr.decodeEntities)(e.name)):(0,Cr.decodeEntities)(e.name)},maxSuggestions:100},a)))}}),"withSelectorProps"),Pr=(0,_r.compose)(Ar,wr,Sr)(kr);var Or=(0,_r.createHigherOrderComponent)((function(e){return function(t){var r=t.onChange,n=ee(t,["onChange"]);return le().createElement(e,Q({onChange:function(e){0!==e.length?r(e[0]):r(null)},maxLength:1},n))}}),"withSingleTermSelectorProps");const Rr=(0,_r.compose)(Or,Ar,wr,Sr)(kr);var Tr="phil",jr="frei",Ir="Weiteres";function qr(e){var t=te((0,de.useEntityProp)("postType",pe().postType,pe().propertyName),2),r=t[0],n=t[1],a=ye().removeError;return[(0,ue.get)(r,e),function(t){a(e),n(Z(r,(function(r){return(0,ue.set)(r,e,t)})))}]}function Dr(){var e,t=te(qr("faculty"),1)[0];return function(e,t){var r=e.map((function(e){return xr(e)})),n=(0,de.useEntityRecords)("taxonomy",t,{include:r,per_page:-1}),a=n.records,i=n.isResolving;return r.length&&a&&!i?a:[]}(null!==(e=null==t?void 0:t.map((function(e){return e.id})))&&void 0!==e?e:[],pe().taxonomySlugs.faculty)}var Fr={BACHELOR:"BA",MASTERS:"MA",TEACHING_DEGREE:"LA"},zr=[Tr,"nat"];function Mr(e){var t,r,n,a=null!==(n=null===(r=null===(t=e.parent)||void 0===t?void 0:t.abbreviation)||void 0===r?void 0:r.de)&&void 0!==n?n:"";return e.abbreviation.de===Fr.BACHELOR||a===Fr.BACHELOR||e.name.de===Ir}function Br(e){var t,r,n,a=null!==(n=null===(r=null===(t=e.parent)||void 0===t?void 0:t.abbreviation)||void 0===r?void 0:r.de)&&void 0!==n?n:"";return e.abbreviation.de===Fr.TEACHING_DEGREE||a===Fr.TEACHING_DEGREE}function Nr(){var e=te(qr("degree"),1)[0];return!!e&&(Mr(e)||Br(e))}function $r(e){var t=te(qr("start"),1)[0];return!!t&&!!t.find((function(t){return t.de===e}))}var Lr={id:"",de:"",en:""};function Hr(e){var t;return e?{en:null!==(t=e.meta.name_en)&&void 0!==t?t:"",de:e.name,id:Er("term",e.id,"name")}:Q({},Lr)}function Wr(e){var t,r,n,a,i;return e?{id:Er("term",e.id),name:{id:Er("term",e.id,"name"),de:e.name,en:null!==(t=e.meta.name_en)&&void 0!==t?t:""},link_text:{id:Er("term_meta",e.id,"link_text"),de:null!==(r=e.meta.link_text)&&void 0!==r?r:"",en:null!==(n=e.meta.link_text_en)&&void 0!==n?n:""},link_url:{id:Er("term_meta",e.id,"link_url"),de:null!==(a=e.meta.link_url)&&void 0!==a?a:"",en:null!==(i=e.meta.link_url_en)&&void 0!==i?i:""}}:{id:"",name:Q({},Lr),link_text:Q({},Lr),link_url:Q({},Lr)}}function Ur(e){var t,r,n=Wr(e);return n.slug=null!==(t=null==e?void 0:e.slug)&&void 0!==t?t:"",e?(n.parent=null!==(r=e.parent_object)&&void 0!==r?r:null,n):n}const Gr=window.wp.mediaUtils;var Vr={"jpg|jpeg|jpe":"image/jpeg",gif:"image/gif",png:"image/png"},Yr={allowedBlockTypes:["core/paragraph","core/image","core/list","core/list-item","core/heading","core/shortcode","core/quote","fau/description-list","fau/description-term","fau/description-details"],codeEditingEnabled:!1};var Kr=Qt.div(Qr||(Qr=ne(["\n\tmargin: 0 0 12px !important;\n\n\t.content-field-blocks-list {\n\t\tborder: 1px solid #757575;\n\t\tpadding: 10px;\n\t}\n"],["\n\tmargin: 0 0 12px !important;\n\n\t.content-field-blocks-list {\n\t\tborder: 1px solid #757575;\n\t\tpadding: 10px;\n\t}\n"]))),Xr=function(e){var t=e.editorRef,r=(0,fe.useDispatch)(ce.store).clearSelectedBlock,n=(0,oe.useCallback)((function(e){t.current&&!t.current.contains(e.target)&&r()}),[t,r]);return(0,oe.useEffect)((function(){return document.body.addEventListener("click",n,{capture:!0}),function(){return document.body.removeEventListener("click",n,{capture:!0})}}),[n]),null},Jr=function(e){var t,r=e.content,n=e.onChange,a=e.required,i=te((0,oe.useState)((0,ae.parse)(r)),2),o=i[0],l=i[1],c=(0,oe.useRef)(null),s=function(e){n((0,ae.serialize)(e))},u=(t=(0,fe.useSelect)((function(e){var t;return null!==(t=e(de.store).canUser("create","media"))&&void 0!==t&&t}),[]),(0,oe.useMemo)((function(){var e;return t&&(e=function(e){var t=e.onError,r=ee(e,["onError"]);(0,Gr.uploadMedia)(Q({wpAllowedMimeTypes:Vr,onError:function(e){var r=e.message;return t(r)}},r))}),Q(Q({},Yr),{mediaUpload:e,__experimentalFetchLinkSuggestions:function(e,t){return(0,de.__experimentalFetchLinkSuggestions)(e,t)},__experimentalFetchRichUrlData:de.__experimentalFetchUrlData})}),[t])),d=vr().required;return le().createElement(ce.BlockEditorProvider,{value:o,onInput:function(e){l(e),s(e)},onChange:function(e){l(e),s(e)},settings:u},le().createElement("div",{ref:c,className:"fau-content-field"},le().createElement(Se.SlotFillProvider,null,le().createElement(Kr,{className:"editor-styles-wrapper"},le().createElement(ce.BlockEditorKeyboardShortcuts.Register,null),le().createElement(ce.BlockTools,null,le().createElement(ce.WritingFlow,null,le().createElement(ce.ObserveTyping,null,le().createElement("div",{role:"textbox","aria-required":null!=a?a:d},le().createElement(ce.BlockList,{renderAppender:ce.DefaultBlockAppender,className:"content-field-blocks-list"}),le().createElement(Xr,{editorRef:c})))))),le().createElement(Se.Popover.Slot,null))))};Jr.defaultProps={required:!1};const Zr=Jr;var Qr;const en=function(e){var t=vr().required;return le().createElement(Se.TextControl,Q({},e,{pattern:"((0[1-9]|[12][0-9]|3[01])\\.(0[13578]|1[02])|(0[1-9]|[12][0-9]|30)\\.(0[469]|11)|(0[1-9]|1[0-9]|2[0-8])\\.02)\\.",placeholder:"TT.MM.",className:"c-day-month-picker","aria-required":t}))},tn=function(){return le().createElement(sr,{isBlock:void 0,fill:"full"},le().createElement("hr",null))};var rn=Object.keys(pe().languages).map((function(e){return{name:e,title:pe().languages[e]}}));const nn=function(e){var t=e.children,r=e.value,n=vr().required;return le().createElement(Se.TabPanel,{tabs:rn.map((function(e){var t="de"!==e.name&&!r[e.name];return Q(Q({},e),{title:t?le().createElement(le().Fragment,null,e.title,le().createElement("small",null,"  (",(0,se._x)("empty","backoffice: Multilingual container","fau-degree-program"),")")):e.title,className:t?"is-empty":""})})),className:"component-multilingual-container"},(function(e){return le().createElement(le().Fragment,null,t(e.name,n))}))},an=function(){var e,t,r=Ee(),n=r.values,a=r.handleChange,i=Nr(),o=function(){var e,t,r=Nr(),n=te(qr("admission_requirements.bachelor_or_teaching_degree"),1)[0];return!!n&&r&&n.name.de!==jr&&(null===(t=null===(e=null==n?void 0:n.parent)||void 0===e?void 0:e.name)||void 0===t?void 0:t.de)!==jr}(),l=function(){var e,t,r=te(qr("degree"),1)[0];return!!r&&(r.abbreviation.de===Fr.MASTERS||(null===(t=null===(e=null==r?void 0:r.parent)||void 0===e?void 0:e.abbreviation)||void 0===t?void 0:t.de)===Fr.MASTERS)}(),c=(e=te(qr("degree"),1)[0],t=Dr(),!(!e||!t.length)&&(Mr(e)||Br(e))&&!!t.find((function(e){return e.slug===Tr}))),s=$r("Sommersemester"),u=$r("Wintersemester");return le().createElement(Se.Panel,null,le().createElement(Se.PanelBody,null,le().createElement(yr,null,(i||o)&&le().createElement(le().Fragment,null,i&&le().createElement(br,{name:"admission_requirements.bachelor_or_teaching_degree",label:(0,se._x)("Admission requirements for Bachelor's/teaching degrees","backoffice: degree program edit form","fau-degree-program"),fill:"half",required:n.degree.name.de!==Ir},le().createElement(Rr,{id:"bachelor_teaching_admission_requirement",taxonomy:"bachelorOrTeachingDegreeAdmissionRequirement",value:n.admission_requirements.bachelor_or_teaching_degree.id,childOnly:!0,onChange:function(e){a("admission_requirements.bachelor_or_teaching_degree",Ur(e))}})),o&&le().createElement(br,{name:"admission_requirements.teaching_degree_higher_semester",label:(0,se._x)("Admission requirements for entering a Bachelor's/teaching degree at a higher semester","backoffice: degree program edit form","fau-degree-program"),fill:"half",required:n.degree.name.de!==Ir},le().createElement(Rr,{id:"teaching_higher_semester_admission_requirement",taxonomy:"teachingDegreeHigherSemesterAdmissionRequirement",value:n.admission_requirements.teaching_degree_higher_semester.id,childOnly:!0,onChange:function(e){a("admission_requirements.teaching_degree_higher_semester",Ur(e))}})),le().createElement(tn,null)),l&&le().createElement(le().Fragment,null,le().createElement(br,{name:"admission_requirements.master",label:(0,se._x)("Admission requirements for Master's degree","backoffice: degree program edit form","fau-degree-program"),required:!0},le().createElement(Rr,{id:"master_admission_requirement",taxonomy:"masterDegreeAdmissionRequirement",value:n.admission_requirements.master.id,childOnly:!0,onChange:function(e){a("admission_requirements.master",Ur(e))}})),le().createElement(br,{name:"content_related_master_requirements",label:(0,se._x)("Content-related admission requirements for Master's degree","backoffice: degree program edit form","fau-degree-program"),help:"vorausgegangene Bachelorstudiengänge, Qualifikationswerte, etc.",required:!0},le().createElement(nn,{value:n.content_related_master_requirements},(function(e,t){return le().createElement(Zr,{key:"content_related_master_requirements.".concat(e),onChange:function(t){a("content_related_master_requirements.".concat(e),t)},content:n.content_related_master_requirements[e],required:t})}))),le().createElement(tn,null)),u&&le().createElement(br,{name:"application_deadline_winter_semester",label:(0,se._x)("Application deadline winter semester","backoffice: degree program edit form","fau-degree-program"),help:"Datum im Format TT.MM. angeben. Weitere Termine können im Feld „Details und Anmerkungen“ eingetragen werden."},le().createElement(en,{onChange:function(e){a("application_deadline_winter_semester",e)},value:n.application_deadline_winter_semester})),s&&le().createElement(br,{name:"application_deadline_summer_semester",label:(0,se._x)("Application deadline summer semester","backoffice: degree program edit form","fau-degree-program"),help:"Datum im Format TT.MM. angeben. Weitere Termine können im Feld „Details und Anmerkungen“ eingetragen werden."},le().createElement(en,{onChange:function(e){a("application_deadline_summer_semester",e)},value:n.application_deadline_summer_semester})),(u||s)&&le().createElement(tn,null),le().createElement(br,{name:"details_and_notes",label:(0,se._x)("Details and notes","backoffice: degree program edit form","fau-degree-program"),help:"evtl. zusätzliche Infos zu Bewerbung und Einschreibung."},le().createElement(nn,{value:n.details_and_notes},(function(e,t){return le().createElement(Zr,{key:"details_and_notes.".concat(e),onChange:function(t){a("details_and_notes.".concat(e),t)},content:n.details_and_notes[e],required:t})}))),le().createElement(br,{name:"language_skills",label:(0,se._x)("Language skills","backoffice: degree program edit form","fau-degree-program"),help:"Sprachkenntnisse, die für den Studiengang erforderlich sind."},le().createElement(nn,{value:n.language_skills},(function(e,t){return le().createElement(Zr,{key:"language_skills.".concat(e),onChange:function(t){a("language_skills.".concat(e),t)},content:n.language_skills[e],required:t})}))),c&&le().createElement(br,{name:"language_skills_humanities_faculty",label:(0,se._x)("Language skills for Faculty of Humanities, Social Sciences, and Theology only","backoffice: degree program edit form","fau-degree-program"),help:"Sprachkenntnisse, die auch in den ersten Semestern noch erworben werden können."},le().createElement(Zr,{key:"language_skills_humanities_faculty",onChange:function(e){a("language_skills_humanities_faculty",e)},content:n.language_skills_humanities_faculty})),le().createElement(br,{name:"german_language_skills_for_international_students",label:(0,se._x)("Language certificates/German language skills for international applicants","backoffice: degree program edit form","fau-degree-program"),required:!0},le().createElement(Rr,{id:"german_language_skills_for_international_students",taxonomy:"germanLanguageSkillsForInternationalStudents",value:n.german_language_skills_for_international_students.id,onChange:function(e){a("german_language_skills_for_international_students",Wr(e))}})))))},on=(0,fe.withSelect)((function(e,t){var r;if(0===t.relatedDegreeProgramIds.length)return{entities:[]};var n=e(de.store.name).getEntityRecords,a=Q({per_page:-1,orderby:"include",_fields:"id,degree_program",context:"view"},{include:t.relatedDegreeProgramIds.join(",")});return{entities:null!==(r=n("postType",pe().postType,a))&&void 0!==r?r:[]}})),ln=(0,fe.withSelect)((function(e,t){var r=te((0,oe.useState)(""),2),n=r[0],a=r[1],i=e(me.store.name).getCurrentPost,o=e(de.store.name).getEntityRecords,l=i(),c=o("postType",pe().postType,Q(Q({per_page:t.maxSuggestions,orderby:"title",order:"asc",_fields:"id,degree_program",context:"view"},{search:n}),l?{exclude:l.id}:{}));return{searchedEntities:null!=c?c:[],setSearch:a}}));var cn=(0,_r.createHigherOrderComponent)((function(e){return function(t){var r=t.setRelatedDegreePrograms,n=ee(t,["setRelatedDegreePrograms"]);return le().createElement(e,Q({entityToToken:function(e){return"".concat((0,Cr.decodeEntities)(e.degree_program.title.de)," (").concat(e.degree_program.degree.abbreviation.de,")")},onChange:function(e){r(e.map((function(e){return e.id})))},maxSuggestions:300},n))}}),"withRelatedDegreeProgramProps");const sn=(0,_r.compose)(cn,on,ln)(kr);function un(){var e,t,r=(e=Dr(),t=te(qr("degree"),1)[0],!(!e.length||!t)&&!!e.find((function(e){return zr.includes(e.slug)}))&&Mr(t)),n=te(qr("combinations"),2),a=n[0],i=n[1],o=te(qr("limited_combinations"),2),l=o[0],c=o[1];return r?void 0===a||void 0===l?le().createElement(Se.Flex,null,le().createElement(Se.FlexBlock,null,le().createElement(Se.Spinner,null))):le().createElement(le().Fragment,null,le().createElement(br,{name:"combinations",label:(0,se._x)("Combinations","backoffice: field label","fau-degree-program")},le().createElement(sn,{relatedDegreeProgramIds:a,setRelatedDegreePrograms:i,messages:{added:(0,se._x)("Combination added","backoffice: field label","fau-degree-program"),removed:(0,se._x)("Combination removed","backoffice: field label","fau-degree-program"),remove:(0,se._x)("Remove combination","backoffice: field label","fau-degree-program"),__experimentalInvalid:(0,se._x)("Invalid combination","backoffice: field label","fau-degree-program")}})),le().createElement(br,{name:"limited_combinations",label:(0,se._x)("Limited Combinations","backoffice: field label","fau-degree-program")},le().createElement(sn,{relatedDegreeProgramIds:l,setRelatedDegreePrograms:c,messages:{added:(0,se._x)("Limited combination added","backoffice: field label","fau-degree-program"),removed:(0,se._x)("Limited combination removed","backoffice: field label","fau-degree-program"),remove:(0,se._x)("Remove limited combination","backoffice: field label","fau-degree-program"),__experimentalInvalid:(0,se._x)("Invalid limited combination","backoffice: field label","fau-degree-program")}}))):null}var dn={about:"kurze Beschreibung des Studiengangs allgemein; ±200 Wörter",structure:"Vorstellung des Fachs und der Studieninhalte; ±200 Wörter",specializations:"Spezialisierungsmöglichkeiten und Schwerpunkte während des Studiums; ±200 Wörter",qualities_and_skills:"Fähigkeiten und Vorlieben der Studieninteressierten, nicht formelle Voraussetzungen; ±200 Wörter",why_should_study:"Einzigartigkeit bzw. Besonderheiten (z. B. Kooperationspartner, Verbundstudiumsangebot) des Studiengangs an der FAU; ±200 Wörter",career_prospects:"mögliche Tätigkeitsfelder nach Abschluss des Studiums; ±200 Wörter",special_features:"Möglichkeiten von Auslandsaufenthalten, Kooperationen mit Forschungsprojekten, etc.; ±200 Wörter"},fn=["about","structure"];const mn=function(){var e=Ee(),t=e.values,r=e.handleChange;return le().createElement(Se.Panel,null,le().createElement(Se.PanelBody,null,le().createElement(yr,null,Object.keys(dn).map((function(e){return le().createElement(br,{key:e,name:"content.".concat(e,".description"),label:"".concat(t.content[e].title.de," ").concat(t.content[e].title.en?"(".concat(t.content[e].title.en,")"):""),help:dn[e],required:fn.includes(e)},le().createElement(nn,{value:t.content[e].description},(function(n,a){return le().createElement(le().Fragment,null,le().createElement(Zr,{key:"content.".concat(e,".description.").concat(n),content:t.content[e].description[n],onChange:function(t){return r("content.".concat(e,".description.").concat(n),t)},required:a}))})))})),le().createElement(un,null))))};var pn=Qt.h1(hn||(hn=ne(["\n\tfont-size: 1.5rem;\n"],["\n\tfont-size: 1.5rem;\n"])));const gn=function(){var e=Ee().values;return le().createElement(pn,null,e.title.de," ",le().createElement("br",null),le().createElement("small",null,e.title.en))};var hn;const vn=window.wp.blob;var bn,yn,kn=Qt.div(yn||(yn=ne(["\n\t.components-placeholder__fieldset {\n\t\t","\n\t\t};\n\t}\n"],["\n\t.components-placeholder__fieldset {\n\t\t","\n\t\t};\n\t}\n"])),(function(e){return e.hasImage?Nt(bn||(bn=ne(["\n\t\t\t\t\t\t.components-form-file-upload,\n\t\t\t\t\t\t.block-editor-media-placeholder__cancel-button,\n\t\t\t\t\t\t.components-button.is-tertiary {\n\t\t\t\t\t\t\tdisplay: none;\n\t\t\t\t\t\t}\n\t\t\t\t "],["\n\t\t\t\t\t\t.components-form-file-upload,\n\t\t\t\t\t\t.block-editor-media-placeholder__cancel-button,\n\t\t\t\t\t\t.components-button.is-tertiary {\n\t\t\t\t\t\t\tdisplay: none;\n\t\t\t\t\t\t}\n\t\t\t\t "]))):""}));function En(e){var t,r=e.path,n=e.title,a=void 0===n?"":n,i=te((0,oe.useState)(!1),2),o=i[0],l=i[1],c=Ee(),s=c.values,u=c.handleChange,d=(t=s[r].id,(0,fe.useSelect)((function(e){return e("core").getMedia(t)}),[t])),f=function(){u(r,{id:0,url:""})},m=function(e){var t=e.id,n=e.url;(0,vn.isBlobURL)(n)?l(!0):(u(r,{id:t,url:n}),l(!1))},p=function(){return!o&&!!(null==d?void 0:d.id)};return le().createElement(ce.MediaUploadCheck,null,le().createElement(kn,{hasImage:p(),"aria-required":vr().required,role:"combobox"},le().createElement(ce.MediaPlaceholder,{value:[s[r].id],onSelect:m,onCancel:p()?f:void 0,allowedTypes:["image"],multiple:!1,labels:{title:a},mediaPreview:le().createElement((function(){var e,t,n,a;return o?le().createElement(Se.Spinner,null):s[r].url?d?le().createElement("img",{width:150,src:null!==(a=null===(n=null===(t=null===(e=null==d?void 0:d.media_details)||void 0===e?void 0:e.sizes)||void 0===t?void 0:t.thumbnail)||void 0===n?void 0:n.source_url)&&void 0!==a?a:s[r].url,alt:"preview"}):le().createElement("div",{style:{width:150,height:150},className:"loader-card"}):null}),null)},p()&&le().createElement(Se.Flex,{gap:4,justify:"flex-start"},le().createElement(ce.MediaReplaceFlow,{mediaUrl:s[r].url,mediaId:s[r].id,allowedTypes:["image"],onSelect:m}),le().createElement(Se.Button,{variant:"primary",isDestructive:!0,onClick:f},(0,se.__)("Remove image"))))))}En.defaultProps={title:""};var xn=Qt.svg(Cn||(Cn=ne(["\n\tstroke: var( --wp-admin-theme-color, #007cba );\n"],["\n\tstroke: var( --wp-admin-theme-color, #007cba );\n"]))),wn=function(e){var t=e.percentage,r=e.squareSize,n=void 0===r?100:r,a=e.strokeWidth,i=void 0===a?2:a,o=(n-i)/2,l="0 0 ".concat(n," ").concat(n),c=o*Math.PI*2,s=c-c*t/100;return le().createElement(xn,{width:n,height:n,viewBox:l},le().createElement("circle",{className:"circle-background",cx:n/2,cy:n/2,r:o,strokeWidth:"".concat(i,"px"),fill:"none",stroke:"rgba(167, 152, 181, 0.3)"}),le().createElement("circle",{className:"circle-progress",cx:n/2,cy:n/2,r:o,fill:"none",strokeWidth:"".concat(i,"px"),transform:"rotate(-90 ".concat(n/2," ").concat(n/2,")"),style:{strokeDasharray:c,strokeDashoffset:s}}))};wn.defaultProps={squareSize:100,strokeWidth:2};const Sn=wn;var Cn,An=function(e){var t=e.maxChars,r=e.children,n=e.value,a=e.required,i=void 0!==a&&a,o=te((0,oe.useState)(t),2),l=o[0],c=o[1];return(0,oe.useEffect)((function(){c(t-n.length)}),[n,t]),le().createElement(le().Fragment,null,r({updatedValue:function(e){return e.length<=t?e:e.substring(0,t)},maxChars:t,required:i}),le().createElement(Se.Flex,{justify:"flex-start"},le().createElement(Sn,{percentage:100*l/t,squareSize:16}),le().createElement("small",null,(0,se._x)("%s characters left","backoffice: limited text input","fau-degree-program").replace("%s",l.toString()))))};An.defaultProps={required:!1};const Pn=An;var On=Qt(Se.Flex)(In||(In=ne(["\n\talign-items: stretch;\n\tmargin-bottom: 5px;\n\n\t> .components-base-control {\n\t\tflex: 1;\n\n\t\t.components-base-control__field,\n\t\t.components-text-control__input {\n\t\t\tmargin-bottom: 0;\n\t\t\theight: 100%;\n\t\t}\n\t}\n"],["\n\talign-items: stretch;\n\tmargin-bottom: 5px;\n\n\t> .components-base-control {\n\t\tflex: 1;\n\n\t\t.components-base-control__field,\n\t\t.components-text-control__input {\n\t\t\tmargin-bottom: 0;\n\t\t\theight: 100%;\n\t\t}\n\t}\n"]))),Rn=Qt.p(qn||(qn=ne(["\n\tbackground-color: #eee;\n\tpadding: 10px;\n\tborder-radius: 2px;\n"],["\n\tbackground-color: #eee;\n\tpadding: 10px;\n\tborder-radius: 2px;\n"]))),Tn=function(e){var t=e.emptyMessage,r=void 0===t?void 0:t,n=e.value,a=e.onChange,i=e.type,o=void 0===i?"text":i,l=e.maxItems,c=n.length?n:[""],s=te((0,oe.useState)(function(e){return e.map((function(e){return{value:e,id:fr()}}))}(c)),2),u=s[0],d=s[1];(0,oe.useEffect)((function(){a(u.filter((function(e){return!!e.value})).map((function(e){return e.value})))}),[u]);var f=vr().required;return le().createElement("div",null,u.map((function(e,t){return le().createElement(On,{key:e.id},le().createElement(Se.TextControl,{value:e.value,onChange:function(e){d(Z(u,(function(r){r[t].value=e})))},type:o,"aria-required":f}),le().createElement(Se.Button,{isDestructive:!0,onClick:function(){d(re([],te(u.filter((function(t){return t.id!==e.id}))),!1))}},le().createElement(Se.Icon,{icon:"no"}),le().createElement(Se.VisuallyHidden,null,(0,se._x)("Remove","backoffice: TextControlCollection","fau-degree-program"))))})),0===u.length&&le().createElement(Rn,null,null!=r?r:(0,se._x)("No items added yet","backoffice: text control collection","fau-degree-program")),(!l||u.length array(), 'version' => '2d0b7e49cb0b1cee1b88'); diff --git a/assets/ts/degree-program-list-table.js b/assets/ts/degree-program-list-table.js new file mode 100644 index 000000000..82b5f2f89 --- /dev/null +++ b/assets/ts/degree-program-list-table.js @@ -0,0 +1 @@ +(()=>{"use strict";({408:function(){var t=this&&this.__assign||function(){return t=Object.assign||function(t){for(var n,s=1,e=arguments.length;s array('wp-dom-ready'), 'version' => 'bb2003dc3111805e9480'); diff --git a/assets/ts/term-meta-fields-validation.js b/assets/ts/term-meta-fields-validation.js new file mode 100644 index 000000000..0cfc9a28c --- /dev/null +++ b/assets/ts/term-meta-fields-validation.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={n:t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return e.d(r,{a:r}),r},d:(t,r)=>{for(var d in r)e.o(r,d)&&!e.o(t,d)&&Object.defineProperty(t,d,{enumerable:!0,get:r[d]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.domReady;e.n(t)()((function(){var e=document.querySelector("#addtag, #edittag"),t=null==e?void 0:e.querySelector("input[type='submit']");e&&t&&e.querySelectorAll(".form-field input").forEach((function(r){r.addEventListener("input",(function(){e.checkValidity()?t.disabled=!1:r.checkValidity()||(t.disabled=!0,e.reportValidity())}))}))}))})(); \ No newline at end of file diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 000000000..e01c8da6f --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,25 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ + private $vendorDir; + + // PSR-4 + /** + * @var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var list + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> + */ + private $prefixesPsr0 = array(); + /** + * @var list + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var array + */ + private $missingClasses = array(); + + /** @var string|null */ + private $apcuPrefix; + + /** + * @var array + */ + private static $registeredLoaders = array(); + + /** + * @param string|null $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return array> + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return list + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return list + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return array Array of classname => path + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders keyed by their corresponding vendor directories. + * + * @return array + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 000000000..51e734a77 --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,359 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints((string) $constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; + } else { + self::$installed = array(); + } + } + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } + + return $installed; + } +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 000000000..f27399a04 --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 000000000..e649fbff0 --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,323 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'Fau\\DegreeProgram\\Application\\DegreeProgramBulkUpdater' => $baseDir . '/src/Application/DegreeProgramBulkUpdater.php', + 'Fau\\DegreeProgram\\Application\\DegreeProgramRetriever' => $baseDir . '/src/Application/DegreeProgramRetriever.php', + 'Fau\\DegreeProgram\\Application\\DegreeProgramUpdater' => $baseDir . '/src/Application/DegreeProgramUpdater.php', + 'Fau\\DegreeProgram\\Application\\Event\\RevisionNotificationCompleted' => $baseDir . '/src/Application/Event/RevisionNotificationCompleted.php', + 'Fau\\DegreeProgram\\Application\\Revision\\DegreeProgramRevision' => $baseDir . '/src/Application/Revision/DegreeProgramRevision.php', + 'Fau\\DegreeProgram\\Application\\Revision\\DegreeProgramRevisionRepository' => $baseDir . '/src/Application/Revision/DegreeProgramRevisionRepository.php', + 'Fau\\DegreeProgram\\Application\\Revision\\RevisionNotificationRepository' => $baseDir . '/src/Application/Revision/RevisionNotificationRepository.php', + 'Fau\\DegreeProgram\\Common\\Application\\AdmissionRequirementTranslated' => $vendorDir . '/rrze/fau-studium-common/src/Application/AdmissionRequirementTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\AdmissionRequirementsTranslated' => $vendorDir . '/rrze/fau-studium-common/src/Application/AdmissionRequirementsTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\Cache\\CacheInvalidator' => $vendorDir . '/rrze/fau-studium-common/src/Application/Cache/CacheInvalidator.php', + 'Fau\\DegreeProgram\\Common\\Application\\Cache\\CacheKeyGenerator' => $vendorDir . '/rrze/fau-studium-common/src/Application/Cache/CacheKeyGenerator.php', + 'Fau\\DegreeProgram\\Common\\Application\\Cache\\CacheWarmer' => $vendorDir . '/rrze/fau-studium-common/src/Application/Cache/CacheWarmer.php', + 'Fau\\DegreeProgram\\Common\\Application\\ConditionalFieldsFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/ConditionalFieldsFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\ContentItemTranslated' => $vendorDir . '/rrze/fau-studium-common/src/Application/ContentItemTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\ContentTranslated' => $vendorDir . '/rrze/fau-studium-common/src/Application/ContentTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\DegreeProgramViewRaw' => $vendorDir . '/rrze/fau-studium-common/src/Application/DegreeProgramViewRaw.php', + 'Fau\\DegreeProgram\\Common\\Application\\DegreeProgramViewTranslated' => $vendorDir . '/rrze/fau-studium-common/src/Application/DegreeProgramViewTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\DegreeTranslated' => $vendorDir . '/rrze/fau-studium-common/src/Application/DegreeTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\Event\\CacheInvalidated' => $vendorDir . '/rrze/fau-studium-common/src/Application/Event/CacheInvalidated.php', + 'Fau\\DegreeProgram\\Common\\Application\\Event\\CacheWarmed' => $vendorDir . '/rrze/fau-studium-common/src/Application/Event/CacheWarmed.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\AdmissionRequirementTypeFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/AdmissionRequirementTypeFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\AreaOfStudyFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/AreaOfStudyFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\ArrayOfIdsFilterTrait' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/ArrayOfIdsFilterTrait.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\AttributeFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/AttributeFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\DegreeFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/DegreeFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\FacultyFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/FacultyFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\Filter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/Filter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\FilterFactory' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/FilterFactory.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\GermanLanguageSkillsForInternationalStudentsFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/GermanLanguageSkillsForInternationalStudentsFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\SearchKeywordFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/SearchKeywordFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\SemesterFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/SemesterFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\StudyLocationFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/StudyLocationFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\SubjectGroupFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/SubjectGroupFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\TeachingLanguageFilter' => $vendorDir . '/rrze/fau-studium-common/src/Application/Filter/TeachingLanguageFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\ImageView' => $vendorDir . '/rrze/fau-studium-common/src/Application/ImageView.php', + 'Fau\\DegreeProgram\\Common\\Application\\JsonSerializer\\CouldNotDeserialize' => $vendorDir . '/rrze/fau-studium-common/src/Application/JsonSerializer/CouldNotDeserialize.php', + 'Fau\\DegreeProgram\\Common\\Application\\JsonSerializer\\JsonSerializable' => $vendorDir . '/rrze/fau-studium-common/src/Application/JsonSerializer/JsonSerializable.php', + 'Fau\\DegreeProgram\\Common\\Application\\JsonSerializer\\JsonSerializer' => $vendorDir . '/rrze/fau-studium-common/src/Application/JsonSerializer/JsonSerializer.php', + 'Fau\\DegreeProgram\\Common\\Application\\Link' => $vendorDir . '/rrze/fau-studium-common/src/Application/Link.php', + 'Fau\\DegreeProgram\\Common\\Application\\Links' => $vendorDir . '/rrze/fau-studium-common/src/Application/Links.php', + 'Fau\\DegreeProgram\\Common\\Application\\Queue\\Message' => $vendorDir . '/rrze/fau-studium-common/src/Application/Queue/Message.php', + 'Fau\\DegreeProgram\\Common\\Application\\Queue\\MessageBus' => $vendorDir . '/rrze/fau-studium-common/src/Application/Queue/MessageBus.php', + 'Fau\\DegreeProgram\\Common\\Application\\Queue\\MessageHandler' => $vendorDir . '/rrze/fau-studium-common/src/Application/Queue/MessageHandler.php', + 'Fau\\DegreeProgram\\Common\\Application\\RelatedDegreeProgram' => $vendorDir . '/rrze/fau-studium-common/src/Application/RelatedDegreeProgram.php', + 'Fau\\DegreeProgram\\Common\\Application\\RelatedDegreePrograms' => $vendorDir . '/rrze/fau-studium-common/src/Application/RelatedDegreePrograms.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\CachedDegreeProgramViewRepository' => $vendorDir . '/rrze/fau-studium-common/src/Application/Repository/CachedDegreeProgramViewRepository.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\CollectionCriteria' => $vendorDir . '/rrze/fau-studium-common/src/Application/Repository/CollectionCriteria.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\DegreeProgramCollectionRepository' => $vendorDir . '/rrze/fau-studium-common/src/Application/Repository/DegreeProgramCollectionRepository.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\DegreeProgramCombinationRepository' => $vendorDir . '/rrze/fau-studium-common/src/Application/Repository/DegreeProgramCombinationRepository.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\DegreeProgramViewRepository' => $vendorDir . '/rrze/fau-studium-common/src/Application/Repository/DegreeProgramViewRepository.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\PaginationAwareCollection' => $vendorDir . '/rrze/fau-studium-common/src/Application/Repository/PaginationAwareCollection.php', + 'Fau\\DegreeProgram\\Common\\Domain\\AdmissionRequirement' => $vendorDir . '/rrze/fau-studium-common/src/Domain/AdmissionRequirement.php', + 'Fau\\DegreeProgram\\Common\\Domain\\AdmissionRequirements' => $vendorDir . '/rrze/fau-studium-common/src/Domain/AdmissionRequirements.php', + 'Fau\\DegreeProgram\\Common\\Domain\\CampoKeys' => $vendorDir . '/rrze/fau-studium-common/src/Domain/CampoKeys.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Content' => $vendorDir . '/rrze/fau-studium-common/src/Domain/Content.php', + 'Fau\\DegreeProgram\\Common\\Domain\\ContentItem' => $vendorDir . '/rrze/fau-studium-common/src/Domain/ContentItem.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Degree' => $vendorDir . '/rrze/fau-studium-common/src/Domain/Degree.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgram' => $vendorDir . '/rrze/fau-studium-common/src/Domain/DegreeProgram.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgramDataValidator' => $vendorDir . '/rrze/fau-studium-common/src/Domain/DegreeProgramDataValidator.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgramId' => $vendorDir . '/rrze/fau-studium-common/src/Domain/DegreeProgramId.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgramIds' => $vendorDir . '/rrze/fau-studium-common/src/Domain/DegreeProgramIds.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgramRepository' => $vendorDir . '/rrze/fau-studium-common/src/Domain/DegreeProgramRepository.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgramSanitizer' => $vendorDir . '/rrze/fau-studium-common/src/Domain/DegreeProgramSanitizer.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Event\\DegreeProgramUpdated' => $vendorDir . '/rrze/fau-studium-common/src/Domain/Event/DegreeProgramUpdated.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Image' => $vendorDir . '/rrze/fau-studium-common/src/Domain/Image.php', + 'Fau\\DegreeProgram\\Common\\Domain\\MultilingualLink' => $vendorDir . '/rrze/fau-studium-common/src/Domain/MultilingualLink.php', + 'Fau\\DegreeProgram\\Common\\Domain\\MultilingualLinks' => $vendorDir . '/rrze/fau-studium-common/src/Domain/MultilingualLinks.php', + 'Fau\\DegreeProgram\\Common\\Domain\\MultilingualList' => $vendorDir . '/rrze/fau-studium-common/src/Domain/MultilingualList.php', + 'Fau\\DegreeProgram\\Common\\Domain\\MultilingualString' => $vendorDir . '/rrze/fau-studium-common/src/Domain/MultilingualString.php', + 'Fau\\DegreeProgram\\Common\\Domain\\NumberOfStudents' => $vendorDir . '/rrze/fau-studium-common/src/Domain/NumberOfStudents.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Violation' => $vendorDir . '/rrze/fau-studium-common/src/Domain/Violation.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Violations' => $vendorDir . '/rrze/fau-studium-common/src/Domain/Violations.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Cache\\PostMetaDegreeProgramCache' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Cache/PostMetaDegreeProgramCache.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Cli\\DegreeProgramCacheCommand' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Cli/DegreeProgramCacheCommand.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\PostType\\DegreeProgramPostType' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/PostType/DegreeProgramPostType.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\ApplyNowLinkTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\AreaOfStudyTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/AreaOfStudyTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\AttributeTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/AttributeTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\BachelorOrTeachingDegreeAdmissionRequirementTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/BachelorOrTeachingDegreeAdmissionRequirementTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\DegreeTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/DegreeTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\ExaminationsOfficeTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/ExaminationsOfficeTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\FacultyTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/FacultyTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\GermanLanguageSkillsForInternationalStudentsTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/GermanLanguageSkillsForInternationalStudentsTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\KeywordTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/KeywordTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\MasterDegreeAdmissionRequirementTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/MasterDegreeAdmissionRequirementTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\NumberOfStudentsTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/NumberOfStudentsTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\SemesterTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/SemesterTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\StudyLocationTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/StudyLocationTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\SubjectGroupTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/SubjectGroupTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\SubjectSpecificAdviceTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/SubjectSpecificAdviceTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\TaxonomiesList' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/TaxonomiesList.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\Taxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/Taxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\TeachingLanguageTaxonomy' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/TeachingLanguageTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Dashboard\\AdminBar\\AdminBarMenu' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/AdminBarMenu.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Dashboard\\AdminBar\\AdminPostAction' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/AdminPostAction.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Dashboard\\AdminBar\\MenuItem' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/MenuItem.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\EventDispatcher\\WordPressHookEventDispatcher' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/EventDispatcher/WordPressHookEventDispatcher.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Logger\\WordPressCliLogger' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Logger/WordPressCliLogger.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Logger\\WordPressLogger' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Logger/WordPressLogger.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Queue\\SyncMessageBus' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Queue/SyncMessageBus.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Queue\\WpCronMessageBus' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Queue/WpCronMessageBus.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\BilingualRepository' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/BilingualRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\CampoKeysRepository' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/CampoKeysRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\FacultyRepository' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/FacultyRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\IdGenerator' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/IdGenerator.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\StickyDegreeProgramRepository' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/StickyDegreeProgramRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WordPressDatabaseDegreeProgramCollectionRepository' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramCollectionRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WordPressDatabaseDegreeProgramRepository' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WordPressDatabaseDegreeProgramViewRepository' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramViewRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WpQueryArgs' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryArgs.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WpQueryArgsBuilder' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryArgsBuilder.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WpQueryPaginationAwareCollection' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryPaginationAwareCollection.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WpQuerySplitter' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Repository/WpQuerySplitter.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\RestApi\\TranslatedDegreeProgramController' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/RestApi/TranslatedDegreeProgramController.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Sanitizer\\HtmlDegreeProgramSanitizer' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Sanitizer/HtmlDegreeProgramSanitizer.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Sanitizer\\SerializedBlocksDegreeProgramSanitizer' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Sanitizer/SerializedBlocksDegreeProgramSanitizer.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\TemplateRenderer\\DirectoryLocator' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/DirectoryLocator.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\TemplateRenderer\\Locator' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/Locator.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\TemplateRenderer\\Renderer' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/Renderer.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\TemplateRenderer\\TemplateRenderer' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/TemplateRenderer.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Validator\\CompositeValidator' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Validator/CompositeValidator.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Validator\\ConditionalFieldsValidator' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Validator/ConditionalFieldsValidator.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Validator\\JsonSchemaDegreeProgramDataValidator' => $vendorDir . '/rrze/fau-studium-common/src/Infrastructure/Validator/JsonSchemaDegreeProgramDataValidator.php', + 'Fau\\DegreeProgram\\Common\\LanguageExtension\\ArrayChangeset' => $vendorDir . '/rrze/fau-studium-common/lib/lang-extension/src/ArrayChangeset.php', + 'Fau\\DegreeProgram\\Common\\LanguageExtension\\ArrayOfStrings' => $vendorDir . '/rrze/fau-studium-common/lib/lang-extension/src/ArrayOfStrings.php', + 'Fau\\DegreeProgram\\Common\\LanguageExtension\\IntegersListChangeset' => $vendorDir . '/rrze/fau-studium-common/lib/lang-extension/src/IntegersListChangeset.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\AuthorizationModule' => $baseDir . '/src/Infrastructure/Authorization/AuthorizationModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities' => $baseDir . '/src/Infrastructure/Authorization/Capabilities.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities\\BlocksCapabilitiesModifier' => $baseDir . '/src/Infrastructure/Authorization/Capabilities/BlocksCapabilitiesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities\\CapabilitiesModifier' => $baseDir . '/src/Infrastructure/Authorization/Capabilities/CapabilitiesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities\\EditPostCapabilitiesModifier' => $baseDir . '/src/Infrastructure/Authorization/Capabilities/EditPostCapabilitiesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities\\MediaCapabilitiesModifier' => $baseDir . '/src/Infrastructure/Authorization/Capabilities/MediaCapabilitiesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities\\PublishDegreeProgramsCapabilitiesModifier' => $baseDir . '/src/Infrastructure/Authorization/Capabilities/PublishDegreeProgramsCapabilitiesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\DeletionDisabler' => $baseDir . '/src/Infrastructure/Authorization/DeletionDisabler.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\Administrator' => $baseDir . '/src/Infrastructure/Authorization/Roles/Administrator.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\CoreRole' => $baseDir . '/src/Infrastructure/Authorization/Roles/CoreRole.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\DegreeProgramAuthor' => $baseDir . '/src/Infrastructure/Authorization/Roles/DegreeProgramAuthor.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\DegreeProgramEditor' => $baseDir . '/src/Infrastructure/Authorization/Roles/DegreeProgramEditor.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\DegreeProgramRole' => $baseDir . '/src/Infrastructure/Authorization/Roles/DegreeProgramRole.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\Editor' => $baseDir . '/src/Infrastructure/Authorization/Roles/Editor.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\Role' => $baseDir . '/src/Infrastructure/Authorization/Roles/Role.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\UserRoleChecker' => $baseDir . '/src/Infrastructure/Authorization/Roles/UserRoleChecker.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\UserRolesModifier' => $baseDir . '/src/Infrastructure/Authorization/UserRolesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\UserRolesRegistrar' => $baseDir . '/src/Infrastructure/Authorization/UserRolesRegistrar.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WordPress22895Fix' => $baseDir . '/src/Infrastructure/Authorization/WordPress22895Fix.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserAdded' => $baseDir . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserAdded.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserDeleted' => $baseDir . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserDeleted.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserRemovedFromSite' => $baseDir . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserRemovedFromSite.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserRoleAdded' => $baseDir . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserRoleAdded.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserRoleRemoved' => $baseDir . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserRoleRemoved.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserUpdated' => $baseDir . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserUpdated.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\WorkflowAuthorModule' => $baseDir . '/src/Infrastructure/Authorization/WorkflowAuthor/WorkflowAuthorModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\WorkflowAuthorTaxonomy' => $baseDir . '/src/Infrastructure/Authorization/WorkflowAuthor/WorkflowAuthorTaxonomy.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\CacheModule' => $baseDir . '/src/Infrastructure/Cache/CacheModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WarmCacheMessage' => $baseDir . '/src/Infrastructure/Cache/WarmCacheMessage.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WarmCacheMessageHandler' => $baseDir . '/src/Infrastructure/Cache/WarmCacheMessageHandler.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WhenCacheInvalidated' => $baseDir . '/src/Infrastructure/Cache/WhenCacheInvalidated.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WhenDegreeProgramSharedPropertyUpdated' => $baseDir . '/src/Infrastructure/Cache/WhenDegreeProgramSharedPropertyUpdated.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WhenDegreeProgramTermUpdated' => $baseDir . '/src/Infrastructure/Cache/WhenDegreeProgramTermUpdated.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WhenDegreeProgramUpdated' => $baseDir . '/src/Infrastructure/Cache/WhenDegreeProgramUpdated.php', + 'Fau\\DegreeProgram\\Infrastructure\\CliModule' => $baseDir . '/src/Infrastructure/CliModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cli\\DegreeProgramRevisionCommand' => $baseDir . '/src/Infrastructure/Cli/DegreeProgramRevisionCommand.php', + 'Fau\\DegreeProgram\\Infrastructure\\Command\\CommandModule' => $baseDir . '/src/Infrastructure/Command/CommandModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Command\\RelatedPostMetaRemover' => $baseDir . '/src/Infrastructure/Command/RelatedPostMetaRemover.php', + 'Fau\\DegreeProgram\\Infrastructure\\Content\\ContentModule' => $baseDir . '/src/Infrastructure/Content/ContentModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Content\\SortableDegreeTaxonomyColumn' => $baseDir . '/src/Infrastructure/Content/SortableDegreeTaxonomyColumn.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\AdminBarModule' => $baseDir . '/src/Infrastructure/Dashboard/AdminBarModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\AssetsLoader' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramEditor/AssetsLoader.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\CodeEditingDisabler' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramEditor/CodeEditingDisabler.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\DegreeProgramEditorModule' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramEditor/DegreeProgramEditorModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\InlineEditingDisabler' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramEditor/InlineEditingDisabler.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\PostTypeEditor' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramEditor/PostTypeEditor.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\PreviewFilter' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramEditor/PreviewFilter.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\ServerDataProvider' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramEditor/ServerDataProvider.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\TaxonomyVisibilityModifier' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramEditor/TaxonomyVisibilityModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\AdminRequest' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramListTable/AdminRequest.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\AssetsLoader' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramListTable/AssetsLoader.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\DegreeProgramListTableModule' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramListTable/DegreeProgramListTableModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\EditPostsQueryModifier' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramListTable/EditPostsQueryModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\StickyColumn' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramListTable/StickyColumn.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\ToggleStickyRequestHandler' => $baseDir . '/src/Infrastructure/Dashboard/DegreeProgramListTable/ToggleStickyRequestHandler.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\BilingualLinkSettingsField' => $baseDir . '/src/Infrastructure/Dashboard/Settings/BilingualLinkSettingsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\BilingualTextSettingsField' => $baseDir . '/src/Infrastructure/Dashboard/Settings/BilingualTextSettingsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\NumericSettingsField' => $baseDir . '/src/Infrastructure/Dashboard/Settings/NumericSettingsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\Option' => $baseDir . '/src/Infrastructure/Dashboard/Settings/Option.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingAssetsLoader' => $baseDir . '/src/Infrastructure/Dashboard/Settings/SettingAssetsLoader.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingsField' => $baseDir . '/src/Infrastructure/Dashboard/Settings/SettingsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingsModule' => $baseDir . '/src/Infrastructure/Dashboard/Settings/SettingsModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingsPage' => $baseDir . '/src/Infrastructure/Dashboard/Settings/SettingsPage.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingsRegistrar' => $baseDir . '/src/Infrastructure/Dashboard/Settings/SettingsRegistrar.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingsSection' => $baseDir . '/src/Infrastructure/Dashboard/Settings/SettingsSection.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\TabbedSettingPage' => $baseDir . '/src/Infrastructure/Dashboard/Settings/TabbedSettingPage.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\TextSettingsField' => $baseDir . '/src/Infrastructure/Dashboard/Settings/TextSettingsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\AssetsLoader' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/AssetsLoader.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\CampoKeyTermMetaField' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/CampoKeyTermMetaField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\EnglishNameTermMetaField' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/EnglishNameTermMetaField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\InputTermMetaField' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/InputTermMetaField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\MultilingualLinkTermMetaFields' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/MultilingualLinkTermMetaFields.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaField' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/TermMetaField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaFieldValidationPattern' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/TermMetaFieldValidationPattern.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaFieldsValidator' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/TermMetaFieldsValidator.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaModule' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/TermMetaModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaRegistrar' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/TermMetaRegistrar.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaRepository' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/TermMetaRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\UrlTermMetaField' => $baseDir . '/src/Infrastructure/Dashboard/TermMeta/UrlTermMetaField.php', + 'Fau\\DegreeProgram\\Infrastructure\\EventDispatcherModule' => $baseDir . '/src/Infrastructure/EventDispatcherModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\LoggerModule' => $baseDir . '/src/Infrastructure/LoggerModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration0010AddInfoBrochureAndStudentInitiativesFields' => $baseDir . '/src/Infrastructure/Migration/Migration0010AddInfoBrochureAndStudentInitiativesFields.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration0014WorkflowAuthorsTermMeta' => $baseDir . '/src/Infrastructure/Migration/Migration0014WorkflowAuthorsTermMeta.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration0015CampoKeyMeta' => $baseDir . '/src/Infrastructure/Migration/Migration0015CampoKeyMeta.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration002TransformVideosMeta' => $baseDir . '/src/Infrastructure/Migration/Migration002TransformVideosMeta.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration11ChangeNumberOfStudentsField' => $baseDir . '/src/Infrastructure/Migration/Migration11ChangeNumberOfStudentsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration13RemoveCustomOrdering' => $baseDir . '/src/Infrastructure/Migration/Migration13RemoveCustomOrdering.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\MigrationModule' => $baseDir . '/src/Infrastructure/Migration/MigrationModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Patches\\FAU171ThemePatch' => $baseDir . '/src/Infrastructure/Patches/FAU171ThemePatch.php', + 'Fau\\DegreeProgram\\Infrastructure\\Patches\\Patch' => $baseDir . '/src/Infrastructure/Patches/Patch.php', + 'Fau\\DegreeProgram\\Infrastructure\\Patches\\PatchesModule' => $baseDir . '/src/Infrastructure/Patches/PatchesModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\QueueModule' => $baseDir . '/src/Infrastructure/QueueModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\CacheBasedRevisionRepository' => $baseDir . '/src/Infrastructure/Repository/CacheBasedRevisionRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\DegreeProgramEditorRepository' => $baseDir . '/src/Infrastructure/Repository/DegreeProgramEditorRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\RepositoryModule' => $baseDir . '/src/Infrastructure/Repository/RepositoryModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\RevisionMetaRepository' => $baseDir . '/src/Infrastructure/Repository/RevisionMetaRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\TermsRepository' => $baseDir . '/src/Infrastructure/Repository/TermsRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\WordPressRevisionNotificationRepository' => $baseDir . '/src/Infrastructure/Repository/WordPressRevisionNotificationRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\WorkflowAuthorsRepository' => $baseDir . '/src/Infrastructure/Repository/WorkflowAuthorsRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\RestApi\\DegreeProgramController' => $baseDir . '/src/Infrastructure/RestApi/DegreeProgramController.php', + 'Fau\\DegreeProgram\\Infrastructure\\RestApi\\DegreeProgramRequestFilter' => $baseDir . '/src/Infrastructure/RestApi/DegreeProgramRequestFilter.php', + 'Fau\\DegreeProgram\\Infrastructure\\RestApi\\RestApiModule' => $baseDir . '/src/Infrastructure/RestApi/RestApiModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\RestApi\\TermsParentObjectController' => $baseDir . '/src/Infrastructure/RestApi/TermsParentObjectController.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\ChangesDetector' => $baseDir . '/src/Infrastructure/Revision/ChangesDetector.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\DailyRevisionNotificationRunner' => $baseDir . '/src/Infrastructure/Revision/DailyRevisionNotificationRunner.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\FieldRetriever' => $baseDir . '/src/Infrastructure/Revision/FieldRetriever.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\Notification\\RevisionDiff' => $baseDir . '/src/Infrastructure/Revision/Notification/RevisionDiff.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\Notification\\RevisionNotificationFormatter' => $baseDir . '/src/Infrastructure/Revision/Notification/RevisionNotificationFormatter.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\Notification\\RevisionNotificationModule' => $baseDir . '/src/Infrastructure/Revision/Notification/RevisionNotificationModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\Notification\\RevisionNotificationSender' => $baseDir . '/src/Infrastructure/Revision/Notification/RevisionNotificationSender.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\Notification\\RevisionNotifier' => $baseDir . '/src/Infrastructure/Revision/Notification/RevisionNotifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\PersistRevision' => $baseDir . '/src/Infrastructure/Revision/PersistRevision.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\PrepareRevisionForJs' => $baseDir . '/src/Infrastructure/Revision/PrepareRevisionForJs.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\ReplaceListOfRevisionableFields' => $baseDir . '/src/Infrastructure/Revision/ReplaceListOfRevisionableFields.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\RestoreRevision' => $baseDir . '/src/Infrastructure/Revision/RestoreRevision.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\RevisionModule' => $baseDir . '/src/Infrastructure/Revision/RevisionModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\RevisionsToKeep' => $baseDir . '/src/Infrastructure/Revision/RevisionsToKeep.php', + 'Fau\\DegreeProgram\\Infrastructure\\SanitizerModule' => $baseDir . '/src/Infrastructure/SanitizerModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\TranslationModule' => $baseDir . '/src/Infrastructure/TranslationModule.php', + 'Inpsyde\\Assets\\Asset' => $vendorDir . '/inpsyde/assets/src/Asset.php', + 'Inpsyde\\Assets\\AssetFactory' => $vendorDir . '/inpsyde/assets/src/AssetFactory.php', + 'Inpsyde\\Assets\\AssetManager' => $vendorDir . '/inpsyde/assets/src/AssetManager.php', + 'Inpsyde\\Assets\\BaseAsset' => $vendorDir . '/inpsyde/assets/src/BaseAsset.php', + 'Inpsyde\\Assets\\ConfigureAutodiscoverVersionTrait' => $vendorDir . '/inpsyde/assets/src/ConfigureAutodiscoverVersionTrait.php', + 'Inpsyde\\Assets\\Exception\\FileNotFoundException' => $vendorDir . '/inpsyde/assets/src/Exception/FileNotFoundException.php', + 'Inpsyde\\Assets\\Exception\\InvalidArgumentException' => $vendorDir . '/inpsyde/assets/src/Exception/InvalidArgumentException.php', + 'Inpsyde\\Assets\\Exception\\InvalidResourceException' => $vendorDir . '/inpsyde/assets/src/Exception/InvalidResourceException.php', + 'Inpsyde\\Assets\\Exception\\MissingArgumentException' => $vendorDir . '/inpsyde/assets/src/Exception/MissingArgumentException.php', + 'Inpsyde\\Assets\\Handler\\AssetHandler' => $vendorDir . '/inpsyde/assets/src/Handler/AssetHandler.php', + 'Inpsyde\\Assets\\Handler\\OutputFilterAwareAssetHandler' => $vendorDir . '/inpsyde/assets/src/Handler/OutputFilterAwareAssetHandler.php', + 'Inpsyde\\Assets\\Handler\\OutputFilterAwareAssetHandlerTrait' => $vendorDir . '/inpsyde/assets/src/Handler/OutputFilterAwareAssetHandlerTrait.php', + 'Inpsyde\\Assets\\Handler\\ScriptHandler' => $vendorDir . '/inpsyde/assets/src/Handler/ScriptHandler.php', + 'Inpsyde\\Assets\\Handler\\StyleHandler' => $vendorDir . '/inpsyde/assets/src/Handler/StyleHandler.php', + 'Inpsyde\\Assets\\Loader\\AbstractWebpackLoader' => $vendorDir . '/inpsyde/assets/src/Loader/AbstractWebpackLoader.php', + 'Inpsyde\\Assets\\Loader\\ArrayLoader' => $vendorDir . '/inpsyde/assets/src/Loader/ArrayLoader.php', + 'Inpsyde\\Assets\\Loader\\EncoreEntrypointsLoader' => $vendorDir . '/inpsyde/assets/src/Loader/EncoreEntrypointsLoader.php', + 'Inpsyde\\Assets\\Loader\\LoaderInterface' => $vendorDir . '/inpsyde/assets/src/Loader/LoaderInterface.php', + 'Inpsyde\\Assets\\Loader\\PhpFileLoader' => $vendorDir . '/inpsyde/assets/src/Loader/PhpFileLoader.php', + 'Inpsyde\\Assets\\Loader\\WebpackManifestLoader' => $vendorDir . '/inpsyde/assets/src/Loader/WebpackManifestLoader.php', + 'Inpsyde\\Assets\\OutputFilter\\AssetOutputFilter' => $vendorDir . '/inpsyde/assets/src/OutputFilter/AssetOutputFilter.php', + 'Inpsyde\\Assets\\OutputFilter\\AsyncScriptOutputFilter' => $vendorDir . '/inpsyde/assets/src/OutputFilter/AsyncScriptOutputFilter.php', + 'Inpsyde\\Assets\\OutputFilter\\AsyncStyleOutputFilter' => $vendorDir . '/inpsyde/assets/src/OutputFilter/AsyncStyleOutputFilter.php', + 'Inpsyde\\Assets\\OutputFilter\\AttributesOutputFilter' => $vendorDir . '/inpsyde/assets/src/OutputFilter/AttributesOutputFilter.php', + 'Inpsyde\\Assets\\OutputFilter\\DeferScriptOutputFilter' => $vendorDir . '/inpsyde/assets/src/OutputFilter/DeferScriptOutputFilter.php', + 'Inpsyde\\Assets\\OutputFilter\\InlineAssetOutputFilter' => $vendorDir . '/inpsyde/assets/src/OutputFilter/InlineAssetOutputFilter.php', + 'Inpsyde\\Assets\\Script' => $vendorDir . '/inpsyde/assets/src/Script.php', + 'Inpsyde\\Assets\\Style' => $vendorDir . '/inpsyde/assets/src/Style.php', + 'Inpsyde\\Assets\\Util\\AssetHookResolver' => $vendorDir . '/inpsyde/assets/src/Util/AssetHookResolver.php', + 'Inpsyde\\Assets\\Util\\AssetPathResolver' => $vendorDir . '/inpsyde/assets/src/Util/AssetPathResolver.php', + 'Inpsyde\\Modularity\\Container\\ContainerConfigurator' => $vendorDir . '/inpsyde/modularity/src/Container/ContainerConfigurator.php', + 'Inpsyde\\Modularity\\Container\\PackageProxyContainer' => $vendorDir . '/inpsyde/modularity/src/Container/PackageProxyContainer.php', + 'Inpsyde\\Modularity\\Container\\ReadOnlyContainer' => $vendorDir . '/inpsyde/modularity/src/Container/ReadOnlyContainer.php', + 'Inpsyde\\Modularity\\Container\\ServiceExtensions' => $vendorDir . '/inpsyde/modularity/src/Container/ServiceExtensions.php', + 'Inpsyde\\Modularity\\Module\\ExecutableModule' => $vendorDir . '/inpsyde/modularity/src/Module/ExecutableModule.php', + 'Inpsyde\\Modularity\\Module\\ExtendingModule' => $vendorDir . '/inpsyde/modularity/src/Module/ExtendingModule.php', + 'Inpsyde\\Modularity\\Module\\FactoryModule' => $vendorDir . '/inpsyde/modularity/src/Module/FactoryModule.php', + 'Inpsyde\\Modularity\\Module\\Module' => $vendorDir . '/inpsyde/modularity/src/Module/Module.php', + 'Inpsyde\\Modularity\\Module\\ModuleClassNameIdTrait' => $vendorDir . '/inpsyde/modularity/src/Module/ModuleClassNameIdTrait.php', + 'Inpsyde\\Modularity\\Module\\ServiceModule' => $vendorDir . '/inpsyde/modularity/src/Module/ServiceModule.php', + 'Inpsyde\\Modularity\\Package' => $vendorDir . '/inpsyde/modularity/src/Package.php', + 'Inpsyde\\Modularity\\Properties\\BaseProperties' => $vendorDir . '/inpsyde/modularity/src/Properties/BaseProperties.php', + 'Inpsyde\\Modularity\\Properties\\LibraryProperties' => $vendorDir . '/inpsyde/modularity/src/Properties/LibraryProperties.php', + 'Inpsyde\\Modularity\\Properties\\PluginProperties' => $vendorDir . '/inpsyde/modularity/src/Properties/PluginProperties.php', + 'Inpsyde\\Modularity\\Properties\\Properties' => $vendorDir . '/inpsyde/modularity/src/Properties/Properties.php', + 'Inpsyde\\Modularity\\Properties\\ThemeProperties' => $vendorDir . '/inpsyde/modularity/src/Properties/ThemeProperties.php', + 'Inpsyde\\WpContext' => $vendorDir . '/inpsyde/wp-context/src/WpContext.php', + 'Psr\\Container\\ContainerExceptionInterface' => $vendorDir . '/psr/container/src/ContainerExceptionInterface.php', + 'Psr\\Container\\ContainerInterface' => $vendorDir . '/psr/container/src/ContainerInterface.php', + 'Psr\\Container\\NotFoundExceptionInterface' => $vendorDir . '/psr/container/src/NotFoundExceptionInterface.php', + 'Psr\\EventDispatcher\\EventDispatcherInterface' => $vendorDir . '/psr/event-dispatcher/src/EventDispatcherInterface.php', + 'Psr\\EventDispatcher\\ListenerProviderInterface' => $vendorDir . '/psr/event-dispatcher/src/ListenerProviderInterface.php', + 'Psr\\EventDispatcher\\StoppableEventInterface' => $vendorDir . '/psr/event-dispatcher/src/StoppableEventInterface.php', + 'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/src/AbstractLogger.php', + 'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/src/InvalidArgumentException.php', + 'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/src/LogLevel.php', + 'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/src/LoggerAwareInterface.php', + 'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/src/LoggerAwareTrait.php', + 'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/src/LoggerInterface.php', + 'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/src/LoggerTrait.php', + 'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/src/NullLogger.php', + 'Psr\\SimpleCache\\CacheException' => $vendorDir . '/psr/simple-cache/src/CacheException.php', + 'Psr\\SimpleCache\\CacheInterface' => $vendorDir . '/psr/simple-cache/src/CacheInterface.php', + 'Psr\\SimpleCache\\InvalidArgumentException' => $vendorDir . '/psr/simple-cache/src/InvalidArgumentException.php', + 'Webmozart\\Assert\\Assert' => $vendorDir . '/webmozart/assert/src/Assert.php', + 'Webmozart\\Assert\\InvalidArgumentException' => $vendorDir . '/webmozart/assert/src/InvalidArgumentException.php', + 'Webmozart\\Assert\\Mixin' => $vendorDir . '/webmozart/assert/src/Mixin.php', +); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php new file mode 100644 index 000000000..52d37c903 --- /dev/null +++ b/vendor/composer/autoload_files.php @@ -0,0 +1,11 @@ + $vendorDir . '/inpsyde/assets/inc/functions.php', + 'd57dd50c5392c5a5044aae288d38e1c5' => $vendorDir . '/inpsyde/assets/inc/bootstrap.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 000000000..15a2ff3ad --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/webmozart/assert/src'), + 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/src'), + 'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'), + 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), + 'Inpsyde\\Modularity\\' => array($vendorDir . '/inpsyde/modularity/src'), + 'Inpsyde\\Assets\\' => array($vendorDir . '/inpsyde/assets/src'), + 'Inpsyde\\' => array($vendorDir . '/inpsyde/wp-context/src'), + 'Fau\\DegreeProgram\\Common\\LanguageExtension\\' => array($vendorDir . '/rrze/fau-studium-common/lib/lang-extension/src'), + 'Fau\\DegreeProgram\\Common\\' => array($vendorDir . '/rrze/fau-studium-common/src'), + 'Fau\\DegreeProgram\\' => array($baseDir . '/src'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 000000000..b27a762fc --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,50 @@ +register(true); + + $filesToLoad = \Composer\Autoload\ComposerStaticInit9b26dc3afea28999db39ee47dc4ef724::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); + } + + return $loader; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 000000000..75d297d87 --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,413 @@ + __DIR__ . '/..' . '/inpsyde/assets/inc/functions.php', + 'd57dd50c5392c5a5044aae288d38e1c5' => __DIR__ . '/..' . '/inpsyde/assets/inc/bootstrap.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'W' => + array ( + 'Webmozart\\Assert\\' => 17, + ), + 'P' => + array ( + 'Psr\\SimpleCache\\' => 16, + 'Psr\\Log\\' => 8, + 'Psr\\EventDispatcher\\' => 20, + 'Psr\\Container\\' => 14, + ), + 'I' => + array ( + 'Inpsyde\\Modularity\\' => 19, + 'Inpsyde\\Assets\\' => 15, + 'Inpsyde\\' => 8, + ), + 'F' => + array ( + 'Fau\\DegreeProgram\\Common\\LanguageExtension\\' => 43, + 'Fau\\DegreeProgram\\Common\\' => 25, + 'Fau\\DegreeProgram\\' => 18, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Webmozart\\Assert\\' => + array ( + 0 => __DIR__ . '/..' . '/webmozart/assert/src', + ), + 'Psr\\SimpleCache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/simple-cache/src', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/src', + ), + 'Psr\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/event-dispatcher/src', + ), + 'Psr\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/container/src', + ), + 'Inpsyde\\Modularity\\' => + array ( + 0 => __DIR__ . '/..' . '/inpsyde/modularity/src', + ), + 'Inpsyde\\Assets\\' => + array ( + 0 => __DIR__ . '/..' . '/inpsyde/assets/src', + ), + 'Inpsyde\\' => + array ( + 0 => __DIR__ . '/..' . '/inpsyde/wp-context/src', + ), + 'Fau\\DegreeProgram\\Common\\LanguageExtension\\' => + array ( + 0 => __DIR__ . '/..' . '/rrze/fau-studium-common/lib/lang-extension/src', + ), + 'Fau\\DegreeProgram\\Common\\' => + array ( + 0 => __DIR__ . '/..' . '/rrze/fau-studium-common/src', + ), + 'Fau\\DegreeProgram\\' => + array ( + 0 => __DIR__ . '/../..' . '/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Fau\\DegreeProgram\\Application\\DegreeProgramBulkUpdater' => __DIR__ . '/../..' . '/src/Application/DegreeProgramBulkUpdater.php', + 'Fau\\DegreeProgram\\Application\\DegreeProgramRetriever' => __DIR__ . '/../..' . '/src/Application/DegreeProgramRetriever.php', + 'Fau\\DegreeProgram\\Application\\DegreeProgramUpdater' => __DIR__ . '/../..' . '/src/Application/DegreeProgramUpdater.php', + 'Fau\\DegreeProgram\\Application\\Event\\RevisionNotificationCompleted' => __DIR__ . '/../..' . '/src/Application/Event/RevisionNotificationCompleted.php', + 'Fau\\DegreeProgram\\Application\\Revision\\DegreeProgramRevision' => __DIR__ . '/../..' . '/src/Application/Revision/DegreeProgramRevision.php', + 'Fau\\DegreeProgram\\Application\\Revision\\DegreeProgramRevisionRepository' => __DIR__ . '/../..' . '/src/Application/Revision/DegreeProgramRevisionRepository.php', + 'Fau\\DegreeProgram\\Application\\Revision\\RevisionNotificationRepository' => __DIR__ . '/../..' . '/src/Application/Revision/RevisionNotificationRepository.php', + 'Fau\\DegreeProgram\\Common\\Application\\AdmissionRequirementTranslated' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/AdmissionRequirementTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\AdmissionRequirementsTranslated' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/AdmissionRequirementsTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\Cache\\CacheInvalidator' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Cache/CacheInvalidator.php', + 'Fau\\DegreeProgram\\Common\\Application\\Cache\\CacheKeyGenerator' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Cache/CacheKeyGenerator.php', + 'Fau\\DegreeProgram\\Common\\Application\\Cache\\CacheWarmer' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Cache/CacheWarmer.php', + 'Fau\\DegreeProgram\\Common\\Application\\ConditionalFieldsFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/ConditionalFieldsFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\ContentItemTranslated' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/ContentItemTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\ContentTranslated' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/ContentTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\DegreeProgramViewRaw' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/DegreeProgramViewRaw.php', + 'Fau\\DegreeProgram\\Common\\Application\\DegreeProgramViewTranslated' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/DegreeProgramViewTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\DegreeTranslated' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/DegreeTranslated.php', + 'Fau\\DegreeProgram\\Common\\Application\\Event\\CacheInvalidated' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Event/CacheInvalidated.php', + 'Fau\\DegreeProgram\\Common\\Application\\Event\\CacheWarmed' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Event/CacheWarmed.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\AdmissionRequirementTypeFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/AdmissionRequirementTypeFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\AreaOfStudyFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/AreaOfStudyFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\ArrayOfIdsFilterTrait' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/ArrayOfIdsFilterTrait.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\AttributeFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/AttributeFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\DegreeFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/DegreeFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\FacultyFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/FacultyFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\Filter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/Filter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\FilterFactory' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/FilterFactory.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\GermanLanguageSkillsForInternationalStudentsFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/GermanLanguageSkillsForInternationalStudentsFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\SearchKeywordFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/SearchKeywordFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\SemesterFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/SemesterFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\StudyLocationFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/StudyLocationFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\SubjectGroupFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/SubjectGroupFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\Filter\\TeachingLanguageFilter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Filter/TeachingLanguageFilter.php', + 'Fau\\DegreeProgram\\Common\\Application\\ImageView' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/ImageView.php', + 'Fau\\DegreeProgram\\Common\\Application\\JsonSerializer\\CouldNotDeserialize' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/JsonSerializer/CouldNotDeserialize.php', + 'Fau\\DegreeProgram\\Common\\Application\\JsonSerializer\\JsonSerializable' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/JsonSerializer/JsonSerializable.php', + 'Fau\\DegreeProgram\\Common\\Application\\JsonSerializer\\JsonSerializer' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/JsonSerializer/JsonSerializer.php', + 'Fau\\DegreeProgram\\Common\\Application\\Link' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Link.php', + 'Fau\\DegreeProgram\\Common\\Application\\Links' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Links.php', + 'Fau\\DegreeProgram\\Common\\Application\\Queue\\Message' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Queue/Message.php', + 'Fau\\DegreeProgram\\Common\\Application\\Queue\\MessageBus' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Queue/MessageBus.php', + 'Fau\\DegreeProgram\\Common\\Application\\Queue\\MessageHandler' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Queue/MessageHandler.php', + 'Fau\\DegreeProgram\\Common\\Application\\RelatedDegreeProgram' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/RelatedDegreeProgram.php', + 'Fau\\DegreeProgram\\Common\\Application\\RelatedDegreePrograms' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/RelatedDegreePrograms.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\CachedDegreeProgramViewRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Repository/CachedDegreeProgramViewRepository.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\CollectionCriteria' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Repository/CollectionCriteria.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\DegreeProgramCollectionRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Repository/DegreeProgramCollectionRepository.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\DegreeProgramCombinationRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Repository/DegreeProgramCombinationRepository.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\DegreeProgramViewRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Repository/DegreeProgramViewRepository.php', + 'Fau\\DegreeProgram\\Common\\Application\\Repository\\PaginationAwareCollection' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Application/Repository/PaginationAwareCollection.php', + 'Fau\\DegreeProgram\\Common\\Domain\\AdmissionRequirement' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/AdmissionRequirement.php', + 'Fau\\DegreeProgram\\Common\\Domain\\AdmissionRequirements' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/AdmissionRequirements.php', + 'Fau\\DegreeProgram\\Common\\Domain\\CampoKeys' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/CampoKeys.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Content' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/Content.php', + 'Fau\\DegreeProgram\\Common\\Domain\\ContentItem' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/ContentItem.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Degree' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/Degree.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgram' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/DegreeProgram.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgramDataValidator' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/DegreeProgramDataValidator.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgramId' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/DegreeProgramId.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgramIds' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/DegreeProgramIds.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgramRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/DegreeProgramRepository.php', + 'Fau\\DegreeProgram\\Common\\Domain\\DegreeProgramSanitizer' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/DegreeProgramSanitizer.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Event\\DegreeProgramUpdated' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/Event/DegreeProgramUpdated.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Image' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/Image.php', + 'Fau\\DegreeProgram\\Common\\Domain\\MultilingualLink' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/MultilingualLink.php', + 'Fau\\DegreeProgram\\Common\\Domain\\MultilingualLinks' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/MultilingualLinks.php', + 'Fau\\DegreeProgram\\Common\\Domain\\MultilingualList' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/MultilingualList.php', + 'Fau\\DegreeProgram\\Common\\Domain\\MultilingualString' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/MultilingualString.php', + 'Fau\\DegreeProgram\\Common\\Domain\\NumberOfStudents' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/NumberOfStudents.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Violation' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/Violation.php', + 'Fau\\DegreeProgram\\Common\\Domain\\Violations' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Domain/Violations.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Cache\\PostMetaDegreeProgramCache' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Cache/PostMetaDegreeProgramCache.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Cli\\DegreeProgramCacheCommand' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Cli/DegreeProgramCacheCommand.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\PostType\\DegreeProgramPostType' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/PostType/DegreeProgramPostType.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\ApplyNowLinkTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\AreaOfStudyTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/AreaOfStudyTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\AttributeTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/AttributeTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\BachelorOrTeachingDegreeAdmissionRequirementTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/BachelorOrTeachingDegreeAdmissionRequirementTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\DegreeTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/DegreeTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\ExaminationsOfficeTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/ExaminationsOfficeTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\FacultyTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/FacultyTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\GermanLanguageSkillsForInternationalStudentsTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/GermanLanguageSkillsForInternationalStudentsTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\KeywordTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/KeywordTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\MasterDegreeAdmissionRequirementTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/MasterDegreeAdmissionRequirementTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\NumberOfStudentsTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/NumberOfStudentsTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\SemesterTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/SemesterTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\StudyLocationTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/StudyLocationTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\SubjectGroupTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/SubjectGroupTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\SubjectSpecificAdviceTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/SubjectSpecificAdviceTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\TaxonomiesList' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/TaxonomiesList.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\Taxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/Taxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Content\\Taxonomy\\TeachingLanguageTaxonomy' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/TeachingLanguageTaxonomy.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Dashboard\\AdminBar\\AdminBarMenu' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/AdminBarMenu.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Dashboard\\AdminBar\\AdminPostAction' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/AdminPostAction.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Dashboard\\AdminBar\\MenuItem' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/MenuItem.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\EventDispatcher\\WordPressHookEventDispatcher' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/EventDispatcher/WordPressHookEventDispatcher.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Logger\\WordPressCliLogger' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Logger/WordPressCliLogger.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Logger\\WordPressLogger' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Logger/WordPressLogger.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Queue\\SyncMessageBus' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Queue/SyncMessageBus.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Queue\\WpCronMessageBus' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Queue/WpCronMessageBus.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\BilingualRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/BilingualRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\CampoKeysRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/CampoKeysRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\FacultyRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/FacultyRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\IdGenerator' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/IdGenerator.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\StickyDegreeProgramRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/StickyDegreeProgramRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WordPressDatabaseDegreeProgramCollectionRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramCollectionRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WordPressDatabaseDegreeProgramRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WordPressDatabaseDegreeProgramViewRepository' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramViewRepository.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WpQueryArgs' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryArgs.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WpQueryArgsBuilder' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryArgsBuilder.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WpQueryPaginationAwareCollection' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryPaginationAwareCollection.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Repository\\WpQuerySplitter' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Repository/WpQuerySplitter.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\RestApi\\TranslatedDegreeProgramController' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/RestApi/TranslatedDegreeProgramController.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Sanitizer\\HtmlDegreeProgramSanitizer' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Sanitizer/HtmlDegreeProgramSanitizer.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Sanitizer\\SerializedBlocksDegreeProgramSanitizer' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Sanitizer/SerializedBlocksDegreeProgramSanitizer.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\TemplateRenderer\\DirectoryLocator' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/DirectoryLocator.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\TemplateRenderer\\Locator' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/Locator.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\TemplateRenderer\\Renderer' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/Renderer.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\TemplateRenderer\\TemplateRenderer' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/TemplateRenderer.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Validator\\CompositeValidator' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Validator/CompositeValidator.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Validator\\ConditionalFieldsValidator' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Validator/ConditionalFieldsValidator.php', + 'Fau\\DegreeProgram\\Common\\Infrastructure\\Validator\\JsonSchemaDegreeProgramDataValidator' => __DIR__ . '/..' . '/rrze/fau-studium-common/src/Infrastructure/Validator/JsonSchemaDegreeProgramDataValidator.php', + 'Fau\\DegreeProgram\\Common\\LanguageExtension\\ArrayChangeset' => __DIR__ . '/..' . '/rrze/fau-studium-common/lib/lang-extension/src/ArrayChangeset.php', + 'Fau\\DegreeProgram\\Common\\LanguageExtension\\ArrayOfStrings' => __DIR__ . '/..' . '/rrze/fau-studium-common/lib/lang-extension/src/ArrayOfStrings.php', + 'Fau\\DegreeProgram\\Common\\LanguageExtension\\IntegersListChangeset' => __DIR__ . '/..' . '/rrze/fau-studium-common/lib/lang-extension/src/IntegersListChangeset.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\AuthorizationModule' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/AuthorizationModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Capabilities.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities\\BlocksCapabilitiesModifier' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Capabilities/BlocksCapabilitiesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities\\CapabilitiesModifier' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Capabilities/CapabilitiesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities\\EditPostCapabilitiesModifier' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Capabilities/EditPostCapabilitiesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities\\MediaCapabilitiesModifier' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Capabilities/MediaCapabilitiesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Capabilities\\PublishDegreeProgramsCapabilitiesModifier' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Capabilities/PublishDegreeProgramsCapabilitiesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\DeletionDisabler' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/DeletionDisabler.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\Administrator' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Roles/Administrator.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\CoreRole' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Roles/CoreRole.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\DegreeProgramAuthor' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Roles/DegreeProgramAuthor.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\DegreeProgramEditor' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Roles/DegreeProgramEditor.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\DegreeProgramRole' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Roles/DegreeProgramRole.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\Editor' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Roles/Editor.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\Role' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Roles/Role.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\Roles\\UserRoleChecker' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/Roles/UserRoleChecker.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\UserRolesModifier' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/UserRolesModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\UserRolesRegistrar' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/UserRolesRegistrar.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WordPress22895Fix' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/WordPress22895Fix.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserAdded' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserAdded.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserDeleted' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserDeleted.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserRemovedFromSite' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserRemovedFromSite.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserRoleAdded' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserRoleAdded.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserRoleRemoved' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserRoleRemoved.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\UpdateWorkflowAuthorsWhenUserUpdated' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/WorkflowAuthor/UpdateWorkflowAuthorsWhenUserUpdated.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\WorkflowAuthorModule' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/WorkflowAuthor/WorkflowAuthorModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Authorization\\WorkflowAuthor\\WorkflowAuthorTaxonomy' => __DIR__ . '/../..' . '/src/Infrastructure/Authorization/WorkflowAuthor/WorkflowAuthorTaxonomy.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\CacheModule' => __DIR__ . '/../..' . '/src/Infrastructure/Cache/CacheModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WarmCacheMessage' => __DIR__ . '/../..' . '/src/Infrastructure/Cache/WarmCacheMessage.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WarmCacheMessageHandler' => __DIR__ . '/../..' . '/src/Infrastructure/Cache/WarmCacheMessageHandler.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WhenCacheInvalidated' => __DIR__ . '/../..' . '/src/Infrastructure/Cache/WhenCacheInvalidated.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WhenDegreeProgramSharedPropertyUpdated' => __DIR__ . '/../..' . '/src/Infrastructure/Cache/WhenDegreeProgramSharedPropertyUpdated.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WhenDegreeProgramTermUpdated' => __DIR__ . '/../..' . '/src/Infrastructure/Cache/WhenDegreeProgramTermUpdated.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cache\\WhenDegreeProgramUpdated' => __DIR__ . '/../..' . '/src/Infrastructure/Cache/WhenDegreeProgramUpdated.php', + 'Fau\\DegreeProgram\\Infrastructure\\CliModule' => __DIR__ . '/../..' . '/src/Infrastructure/CliModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Cli\\DegreeProgramRevisionCommand' => __DIR__ . '/../..' . '/src/Infrastructure/Cli/DegreeProgramRevisionCommand.php', + 'Fau\\DegreeProgram\\Infrastructure\\Command\\CommandModule' => __DIR__ . '/../..' . '/src/Infrastructure/Command/CommandModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Command\\RelatedPostMetaRemover' => __DIR__ . '/../..' . '/src/Infrastructure/Command/RelatedPostMetaRemover.php', + 'Fau\\DegreeProgram\\Infrastructure\\Content\\ContentModule' => __DIR__ . '/../..' . '/src/Infrastructure/Content/ContentModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Content\\SortableDegreeTaxonomyColumn' => __DIR__ . '/../..' . '/src/Infrastructure/Content/SortableDegreeTaxonomyColumn.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\AdminBarModule' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/AdminBarModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\AssetsLoader' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramEditor/AssetsLoader.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\CodeEditingDisabler' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramEditor/CodeEditingDisabler.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\DegreeProgramEditorModule' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramEditor/DegreeProgramEditorModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\InlineEditingDisabler' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramEditor/InlineEditingDisabler.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\PostTypeEditor' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramEditor/PostTypeEditor.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\PreviewFilter' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramEditor/PreviewFilter.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\ServerDataProvider' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramEditor/ServerDataProvider.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramEditor\\TaxonomyVisibilityModifier' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramEditor/TaxonomyVisibilityModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\AdminRequest' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramListTable/AdminRequest.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\AssetsLoader' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramListTable/AssetsLoader.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\DegreeProgramListTableModule' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramListTable/DegreeProgramListTableModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\EditPostsQueryModifier' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramListTable/EditPostsQueryModifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\StickyColumn' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramListTable/StickyColumn.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\DegreeProgramListTable\\ToggleStickyRequestHandler' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/DegreeProgramListTable/ToggleStickyRequestHandler.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\BilingualLinkSettingsField' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/BilingualLinkSettingsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\BilingualTextSettingsField' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/BilingualTextSettingsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\NumericSettingsField' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/NumericSettingsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\Option' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/Option.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingAssetsLoader' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/SettingAssetsLoader.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingsField' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/SettingsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingsModule' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/SettingsModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingsPage' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/SettingsPage.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingsRegistrar' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/SettingsRegistrar.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\SettingsSection' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/SettingsSection.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\TabbedSettingPage' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/TabbedSettingPage.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\Settings\\TextSettingsField' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/Settings/TextSettingsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\AssetsLoader' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/AssetsLoader.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\CampoKeyTermMetaField' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/CampoKeyTermMetaField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\EnglishNameTermMetaField' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/EnglishNameTermMetaField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\InputTermMetaField' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/InputTermMetaField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\MultilingualLinkTermMetaFields' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/MultilingualLinkTermMetaFields.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaField' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/TermMetaField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaFieldValidationPattern' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/TermMetaFieldValidationPattern.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaFieldsValidator' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/TermMetaFieldsValidator.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaModule' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/TermMetaModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaRegistrar' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/TermMetaRegistrar.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\TermMetaRepository' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/TermMetaRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Dashboard\\TermMeta\\UrlTermMetaField' => __DIR__ . '/../..' . '/src/Infrastructure/Dashboard/TermMeta/UrlTermMetaField.php', + 'Fau\\DegreeProgram\\Infrastructure\\EventDispatcherModule' => __DIR__ . '/../..' . '/src/Infrastructure/EventDispatcherModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\LoggerModule' => __DIR__ . '/../..' . '/src/Infrastructure/LoggerModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration0010AddInfoBrochureAndStudentInitiativesFields' => __DIR__ . '/../..' . '/src/Infrastructure/Migration/Migration0010AddInfoBrochureAndStudentInitiativesFields.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration0014WorkflowAuthorsTermMeta' => __DIR__ . '/../..' . '/src/Infrastructure/Migration/Migration0014WorkflowAuthorsTermMeta.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration0015CampoKeyMeta' => __DIR__ . '/../..' . '/src/Infrastructure/Migration/Migration0015CampoKeyMeta.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration002TransformVideosMeta' => __DIR__ . '/../..' . '/src/Infrastructure/Migration/Migration002TransformVideosMeta.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration11ChangeNumberOfStudentsField' => __DIR__ . '/../..' . '/src/Infrastructure/Migration/Migration11ChangeNumberOfStudentsField.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\Migration13RemoveCustomOrdering' => __DIR__ . '/../..' . '/src/Infrastructure/Migration/Migration13RemoveCustomOrdering.php', + 'Fau\\DegreeProgram\\Infrastructure\\Migration\\MigrationModule' => __DIR__ . '/../..' . '/src/Infrastructure/Migration/MigrationModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Patches\\FAU171ThemePatch' => __DIR__ . '/../..' . '/src/Infrastructure/Patches/FAU171ThemePatch.php', + 'Fau\\DegreeProgram\\Infrastructure\\Patches\\Patch' => __DIR__ . '/../..' . '/src/Infrastructure/Patches/Patch.php', + 'Fau\\DegreeProgram\\Infrastructure\\Patches\\PatchesModule' => __DIR__ . '/../..' . '/src/Infrastructure/Patches/PatchesModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\QueueModule' => __DIR__ . '/../..' . '/src/Infrastructure/QueueModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\CacheBasedRevisionRepository' => __DIR__ . '/../..' . '/src/Infrastructure/Repository/CacheBasedRevisionRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\DegreeProgramEditorRepository' => __DIR__ . '/../..' . '/src/Infrastructure/Repository/DegreeProgramEditorRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\RepositoryModule' => __DIR__ . '/../..' . '/src/Infrastructure/Repository/RepositoryModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\RevisionMetaRepository' => __DIR__ . '/../..' . '/src/Infrastructure/Repository/RevisionMetaRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\TermsRepository' => __DIR__ . '/../..' . '/src/Infrastructure/Repository/TermsRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\WordPressRevisionNotificationRepository' => __DIR__ . '/../..' . '/src/Infrastructure/Repository/WordPressRevisionNotificationRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\Repository\\WorkflowAuthorsRepository' => __DIR__ . '/../..' . '/src/Infrastructure/Repository/WorkflowAuthorsRepository.php', + 'Fau\\DegreeProgram\\Infrastructure\\RestApi\\DegreeProgramController' => __DIR__ . '/../..' . '/src/Infrastructure/RestApi/DegreeProgramController.php', + 'Fau\\DegreeProgram\\Infrastructure\\RestApi\\DegreeProgramRequestFilter' => __DIR__ . '/../..' . '/src/Infrastructure/RestApi/DegreeProgramRequestFilter.php', + 'Fau\\DegreeProgram\\Infrastructure\\RestApi\\RestApiModule' => __DIR__ . '/../..' . '/src/Infrastructure/RestApi/RestApiModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\RestApi\\TermsParentObjectController' => __DIR__ . '/../..' . '/src/Infrastructure/RestApi/TermsParentObjectController.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\ChangesDetector' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/ChangesDetector.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\DailyRevisionNotificationRunner' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/DailyRevisionNotificationRunner.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\FieldRetriever' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/FieldRetriever.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\Notification\\RevisionDiff' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/Notification/RevisionDiff.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\Notification\\RevisionNotificationFormatter' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/Notification/RevisionNotificationFormatter.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\Notification\\RevisionNotificationModule' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/Notification/RevisionNotificationModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\Notification\\RevisionNotificationSender' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/Notification/RevisionNotificationSender.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\Notification\\RevisionNotifier' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/Notification/RevisionNotifier.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\PersistRevision' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/PersistRevision.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\PrepareRevisionForJs' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/PrepareRevisionForJs.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\ReplaceListOfRevisionableFields' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/ReplaceListOfRevisionableFields.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\RestoreRevision' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/RestoreRevision.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\RevisionModule' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/RevisionModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\Revision\\RevisionsToKeep' => __DIR__ . '/../..' . '/src/Infrastructure/Revision/RevisionsToKeep.php', + 'Fau\\DegreeProgram\\Infrastructure\\SanitizerModule' => __DIR__ . '/../..' . '/src/Infrastructure/SanitizerModule.php', + 'Fau\\DegreeProgram\\Infrastructure\\TranslationModule' => __DIR__ . '/../..' . '/src/Infrastructure/TranslationModule.php', + 'Inpsyde\\Assets\\Asset' => __DIR__ . '/..' . '/inpsyde/assets/src/Asset.php', + 'Inpsyde\\Assets\\AssetFactory' => __DIR__ . '/..' . '/inpsyde/assets/src/AssetFactory.php', + 'Inpsyde\\Assets\\AssetManager' => __DIR__ . '/..' . '/inpsyde/assets/src/AssetManager.php', + 'Inpsyde\\Assets\\BaseAsset' => __DIR__ . '/..' . '/inpsyde/assets/src/BaseAsset.php', + 'Inpsyde\\Assets\\ConfigureAutodiscoverVersionTrait' => __DIR__ . '/..' . '/inpsyde/assets/src/ConfigureAutodiscoverVersionTrait.php', + 'Inpsyde\\Assets\\Exception\\FileNotFoundException' => __DIR__ . '/..' . '/inpsyde/assets/src/Exception/FileNotFoundException.php', + 'Inpsyde\\Assets\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/inpsyde/assets/src/Exception/InvalidArgumentException.php', + 'Inpsyde\\Assets\\Exception\\InvalidResourceException' => __DIR__ . '/..' . '/inpsyde/assets/src/Exception/InvalidResourceException.php', + 'Inpsyde\\Assets\\Exception\\MissingArgumentException' => __DIR__ . '/..' . '/inpsyde/assets/src/Exception/MissingArgumentException.php', + 'Inpsyde\\Assets\\Handler\\AssetHandler' => __DIR__ . '/..' . '/inpsyde/assets/src/Handler/AssetHandler.php', + 'Inpsyde\\Assets\\Handler\\OutputFilterAwareAssetHandler' => __DIR__ . '/..' . '/inpsyde/assets/src/Handler/OutputFilterAwareAssetHandler.php', + 'Inpsyde\\Assets\\Handler\\OutputFilterAwareAssetHandlerTrait' => __DIR__ . '/..' . '/inpsyde/assets/src/Handler/OutputFilterAwareAssetHandlerTrait.php', + 'Inpsyde\\Assets\\Handler\\ScriptHandler' => __DIR__ . '/..' . '/inpsyde/assets/src/Handler/ScriptHandler.php', + 'Inpsyde\\Assets\\Handler\\StyleHandler' => __DIR__ . '/..' . '/inpsyde/assets/src/Handler/StyleHandler.php', + 'Inpsyde\\Assets\\Loader\\AbstractWebpackLoader' => __DIR__ . '/..' . '/inpsyde/assets/src/Loader/AbstractWebpackLoader.php', + 'Inpsyde\\Assets\\Loader\\ArrayLoader' => __DIR__ . '/..' . '/inpsyde/assets/src/Loader/ArrayLoader.php', + 'Inpsyde\\Assets\\Loader\\EncoreEntrypointsLoader' => __DIR__ . '/..' . '/inpsyde/assets/src/Loader/EncoreEntrypointsLoader.php', + 'Inpsyde\\Assets\\Loader\\LoaderInterface' => __DIR__ . '/..' . '/inpsyde/assets/src/Loader/LoaderInterface.php', + 'Inpsyde\\Assets\\Loader\\PhpFileLoader' => __DIR__ . '/..' . '/inpsyde/assets/src/Loader/PhpFileLoader.php', + 'Inpsyde\\Assets\\Loader\\WebpackManifestLoader' => __DIR__ . '/..' . '/inpsyde/assets/src/Loader/WebpackManifestLoader.php', + 'Inpsyde\\Assets\\OutputFilter\\AssetOutputFilter' => __DIR__ . '/..' . '/inpsyde/assets/src/OutputFilter/AssetOutputFilter.php', + 'Inpsyde\\Assets\\OutputFilter\\AsyncScriptOutputFilter' => __DIR__ . '/..' . '/inpsyde/assets/src/OutputFilter/AsyncScriptOutputFilter.php', + 'Inpsyde\\Assets\\OutputFilter\\AsyncStyleOutputFilter' => __DIR__ . '/..' . '/inpsyde/assets/src/OutputFilter/AsyncStyleOutputFilter.php', + 'Inpsyde\\Assets\\OutputFilter\\AttributesOutputFilter' => __DIR__ . '/..' . '/inpsyde/assets/src/OutputFilter/AttributesOutputFilter.php', + 'Inpsyde\\Assets\\OutputFilter\\DeferScriptOutputFilter' => __DIR__ . '/..' . '/inpsyde/assets/src/OutputFilter/DeferScriptOutputFilter.php', + 'Inpsyde\\Assets\\OutputFilter\\InlineAssetOutputFilter' => __DIR__ . '/..' . '/inpsyde/assets/src/OutputFilter/InlineAssetOutputFilter.php', + 'Inpsyde\\Assets\\Script' => __DIR__ . '/..' . '/inpsyde/assets/src/Script.php', + 'Inpsyde\\Assets\\Style' => __DIR__ . '/..' . '/inpsyde/assets/src/Style.php', + 'Inpsyde\\Assets\\Util\\AssetHookResolver' => __DIR__ . '/..' . '/inpsyde/assets/src/Util/AssetHookResolver.php', + 'Inpsyde\\Assets\\Util\\AssetPathResolver' => __DIR__ . '/..' . '/inpsyde/assets/src/Util/AssetPathResolver.php', + 'Inpsyde\\Modularity\\Container\\ContainerConfigurator' => __DIR__ . '/..' . '/inpsyde/modularity/src/Container/ContainerConfigurator.php', + 'Inpsyde\\Modularity\\Container\\PackageProxyContainer' => __DIR__ . '/..' . '/inpsyde/modularity/src/Container/PackageProxyContainer.php', + 'Inpsyde\\Modularity\\Container\\ReadOnlyContainer' => __DIR__ . '/..' . '/inpsyde/modularity/src/Container/ReadOnlyContainer.php', + 'Inpsyde\\Modularity\\Container\\ServiceExtensions' => __DIR__ . '/..' . '/inpsyde/modularity/src/Container/ServiceExtensions.php', + 'Inpsyde\\Modularity\\Module\\ExecutableModule' => __DIR__ . '/..' . '/inpsyde/modularity/src/Module/ExecutableModule.php', + 'Inpsyde\\Modularity\\Module\\ExtendingModule' => __DIR__ . '/..' . '/inpsyde/modularity/src/Module/ExtendingModule.php', + 'Inpsyde\\Modularity\\Module\\FactoryModule' => __DIR__ . '/..' . '/inpsyde/modularity/src/Module/FactoryModule.php', + 'Inpsyde\\Modularity\\Module\\Module' => __DIR__ . '/..' . '/inpsyde/modularity/src/Module/Module.php', + 'Inpsyde\\Modularity\\Module\\ModuleClassNameIdTrait' => __DIR__ . '/..' . '/inpsyde/modularity/src/Module/ModuleClassNameIdTrait.php', + 'Inpsyde\\Modularity\\Module\\ServiceModule' => __DIR__ . '/..' . '/inpsyde/modularity/src/Module/ServiceModule.php', + 'Inpsyde\\Modularity\\Package' => __DIR__ . '/..' . '/inpsyde/modularity/src/Package.php', + 'Inpsyde\\Modularity\\Properties\\BaseProperties' => __DIR__ . '/..' . '/inpsyde/modularity/src/Properties/BaseProperties.php', + 'Inpsyde\\Modularity\\Properties\\LibraryProperties' => __DIR__ . '/..' . '/inpsyde/modularity/src/Properties/LibraryProperties.php', + 'Inpsyde\\Modularity\\Properties\\PluginProperties' => __DIR__ . '/..' . '/inpsyde/modularity/src/Properties/PluginProperties.php', + 'Inpsyde\\Modularity\\Properties\\Properties' => __DIR__ . '/..' . '/inpsyde/modularity/src/Properties/Properties.php', + 'Inpsyde\\Modularity\\Properties\\ThemeProperties' => __DIR__ . '/..' . '/inpsyde/modularity/src/Properties/ThemeProperties.php', + 'Inpsyde\\WpContext' => __DIR__ . '/..' . '/inpsyde/wp-context/src/WpContext.php', + 'Psr\\Container\\ContainerExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerExceptionInterface.php', + 'Psr\\Container\\ContainerInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerInterface.php', + 'Psr\\Container\\NotFoundExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/NotFoundExceptionInterface.php', + 'Psr\\EventDispatcher\\EventDispatcherInterface' => __DIR__ . '/..' . '/psr/event-dispatcher/src/EventDispatcherInterface.php', + 'Psr\\EventDispatcher\\ListenerProviderInterface' => __DIR__ . '/..' . '/psr/event-dispatcher/src/ListenerProviderInterface.php', + 'Psr\\EventDispatcher\\StoppableEventInterface' => __DIR__ . '/..' . '/psr/event-dispatcher/src/StoppableEventInterface.php', + 'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/src/AbstractLogger.php', + 'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/src/InvalidArgumentException.php', + 'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/src/LogLevel.php', + 'Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/src/LoggerAwareInterface.php', + 'Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/src/LoggerAwareTrait.php', + 'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/src/LoggerInterface.php', + 'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/src/LoggerTrait.php', + 'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/src/NullLogger.php', + 'Psr\\SimpleCache\\CacheException' => __DIR__ . '/..' . '/psr/simple-cache/src/CacheException.php', + 'Psr\\SimpleCache\\CacheInterface' => __DIR__ . '/..' . '/psr/simple-cache/src/CacheInterface.php', + 'Psr\\SimpleCache\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/simple-cache/src/InvalidArgumentException.php', + 'Webmozart\\Assert\\Assert' => __DIR__ . '/..' . '/webmozart/assert/src/Assert.php', + 'Webmozart\\Assert\\InvalidArgumentException' => __DIR__ . '/..' . '/webmozart/assert/src/InvalidArgumentException.php', + 'Webmozart\\Assert\\Mixin' => __DIR__ . '/..' . '/webmozart/assert/src/Mixin.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit9b26dc3afea28999db39ee47dc4ef724::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit9b26dc3afea28999db39ee47dc4ef724::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit9b26dc3afea28999db39ee47dc4ef724::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 000000000..d205e73ff --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,575 @@ +{ + "packages": [ + { + "name": "inpsyde/assets", + "version": "2.8.3", + "version_normalized": "2.8.3.0", + "source": { + "type": "git", + "url": "https://github.com/inpsyde/assets.git", + "reference": "f198d7d8b726132851413a6a9b4918e02c077a4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/inpsyde/assets/zipball/f198d7d8b726132851413a6a9b4918e02c077a4b", + "reference": "f198d7d8b726132851413a6a9b4918e02c077a4b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "inpsyde/wp-context": "^1.3", + "php": ">=7.2" + }, + "require-dev": { + "brain/monkey": "^2.5.0", + "inpsyde/php-coding-standards": "^1", + "johnpbloch/wordpress-core": ">=6.0", + "mikey179/vfsstream": "^1.6.8", + "php-stubs/wordpress-stubs": ">=6.0@stable", + "phpunit/phpunit": "^8.5.14 || ^9.0", + "vimeo/psalm": "@stable" + }, + "time": "2022-12-16T13:23:02+00:00", + "type": "library", + "extra": { + "wordpress-install-dir": "vendor/wordpress/wordpress" + }, + "installation-source": "dist", + "autoload": { + "files": [ + "inc/functions.php", + "inc/bootstrap.php" + ], + "psr-4": { + "Inpsyde\\Assets\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Inpsyde", + "email": "hello@inpsyde.com", + "homepage": "https://inpsyde.com", + "role": "Company" + }, + { + "name": "Christian Leucht", + "email": "c.leucht@inpsyde.com", + "homepage": "https://www.chrico.info", + "role": "Developer" + } + ], + "description": "Package to manage assets in WordPress.", + "support": { + "issues": "https://github.com/inpsyde/assets/issues", + "source": "https://github.com/inpsyde/assets/tree/2.8.3" + }, + "install-path": "../inpsyde/assets" + }, + { + "name": "inpsyde/modularity", + "version": "1.8.0", + "version_normalized": "1.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/inpsyde/modularity.git", + "reference": "c6855a6d9c4ce6f090d031e820f176bddf2a0b1c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/inpsyde/modularity/zipball/c6855a6d9c4ce6f090d031e820f176bddf2a0b1c", + "reference": "c6855a6d9c4ce6f090d031e820f176bddf2a0b1c", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.2", + "psr/container": "^1.1.0 || ^2" + }, + "require-dev": { + "brain/monkey": "^2.6.1", + "inpsyde/php-coding-standards": "^1", + "johnpbloch/wordpress-core": ">=5.8", + "mikey179/vfsstream": "^v1.6.10", + "php-stubs/wordpress-stubs": ">=5.8@stable", + "phpunit/phpunit": "^8.5.21 || ^9.6.7", + "vimeo/psalm": "^4.13.1" + }, + "time": "2024-05-14T06:07:35+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Inpsyde\\Modularity\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Inpsyde GmbH", + "email": "hello@inpsyde.com", + "homepage": "https://inpsyde.com/", + "role": "Company" + }, + { + "name": "Christian Leucht", + "email": "c.leucht@inpsyde.com", + "role": "Developer" + }, + { + "name": "Giuseppe Mazzapica", + "email": "g.mazzapica@inpsyde.com", + "role": "Developer" + } + ], + "description": "Modular PSR-11 implementation for WordPress plugins, themes or libraries.", + "support": { + "issues": "https://github.com/inpsyde/modularity/issues", + "source": "https://github.com/inpsyde/modularity/tree/1.8.0" + }, + "install-path": "../inpsyde/modularity" + }, + { + "name": "inpsyde/wp-context", + "version": "1.5.0", + "version_normalized": "1.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/inpsyde/wp-context.git", + "reference": "1f61ccb539e287e2688dfdf86dea0448c18fc8c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/inpsyde/wp-context/zipball/1f61ccb539e287e2688dfdf86dea0448c18fc8c6", + "reference": "1f61ccb539e287e2688dfdf86dea0448c18fc8c6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "brain/monkey": "^2.6.1", + "inpsyde/php-coding-standards": "^1", + "inpsyde/wp-stubs": "dev-main", + "mockery/mockery": "~1.3.6", + "phpunit/phpunit": "~7.5.20 || ^8", + "vimeo/psalm": "^4.27.0" + }, + "time": "2023-01-09T06:27:09+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Inpsyde\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "gpl-2.0-or-later" + ], + "authors": [ + { + "name": "Inpsyde GmbH", + "email": "hello@inpsyde.com", + "homepage": "https://inpsyde.com/", + "role": "Company" + }, + { + "name": "Giuseppe Mazzapica", + "email": "g.mazzapica@inpsyde.com", + "role": "Developer" + } + ], + "description": "A single-class utility to check the running context in WordPress sites.", + "support": { + "issues": "https://github.com/inpsyde/wp-context/issues", + "source": "https://github.com/inpsyde/wp-context/tree/1.5.0" + }, + "install-path": "../inpsyde/wp-context" + }, + { + "name": "psr/container", + "version": "2.0.2", + "version_normalized": "2.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "time": "2021-11-05T16:47:00+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "install-path": "../psr/container" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "time": "2019-01-08T18:20:26+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "install-path": "../psr/event-dispatcher" + }, + { + "name": "psr/log", + "version": "3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "time": "2021-07-14T16:46:02+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "install-path": "../psr/log" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "time": "2021-10-29T13:26:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "install-path": "../psr/simple-cache" + }, + { + "name": "rrze/fau-studium-common", + "version": "dev-main", + "version_normalized": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/RRZE-Webteam/FAU-Studium-Common.git", + "reference": "d8cb53c2cf24a6f28b07109cec9bb67c1d51d743" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/RRZE-Webteam/FAU-Studium-Common/zipball/d8cb53c2cf24a6f28b07109cec9bb67c1d51d743", + "reference": "d8cb53c2cf24a6f28b07109cec9bb67c1d51d743", + "shasum": "" + }, + "require": { + "php": "^8.0", + "psr/event-dispatcher": "^1.0", + "psr/log": "^3.0", + "psr/simple-cache": "^3.0", + "webmozart/assert": "^1.11" + }, + "require-dev": { + "brain/monkey": "^2.6", + "inpsyde/php-coding-standards": "^1", + "inpsyde/wp-stubs-versions": "dev-latest", + "johnpbloch/wordpress-core": "^6.1", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.4", + "wp-cli/wp-cli": "^2.7" + }, + "suggest": { + "inpsyde/modularity": "Modular PSR-11 implementation for WordPress Plugins, Themes or Libraries" + }, + "time": "2024-07-23T13:46:52+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Fau\\DegreeProgram\\Common\\": "src/", + "Fau\\DegreeProgram\\Common\\LanguageExtension\\": "lib/lang-extension/src/" + } + }, + "autoload-dev": { + "psr-4": { + "Fau\\DegreeProgram\\Common\\Tests\\": [ + "tests/src/", + "tests/unit/", + "tests/functional/" + ], + "Fau\\DegreeProgram\\Common\\LanguageExtension\\Tests\\": "lib/lang-extension/tests/" + } + }, + "scripts": { + "check-coding-standards": [ + "vendor/bin/phpcs" + ], + "check-psalm": [ + "vendor/bin/psalm --no-cache" + ], + "fix-coding-standards": [ + "vendor/bin/phpcbf" + ], + "tests": [ + "@php ./vendor/phpunit/phpunit/phpunit --coverage-text" + ], + "tests:no-cov": [ + "@php ./vendor/phpunit/phpunit/phpunit --no-coverage" + ] + }, + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Syde GmbH", + "email": "hello@syde.com", + "homepage": "https://syde.com/", + "role": "Company" + } + ], + "description": "Shared kernel for FAU Degree Program and FAU Degree Program Output plugins.", + "support": { + "source": "https://github.com/RRZE-Webteam/FAU-Studium-Common/tree/main", + "issues": "https://github.com/RRZE-Webteam/FAU-Studium-Common/issues" + }, + "install-path": "../rrze/fau-studium-common" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "version_normalized": "1.11.0.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "time": "2022-06-03T18:03:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "install-path": "../webmozart/assert" + } + ], + "dev": false, + "dev-package-names": [] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 000000000..0cd36ddc3 --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,104 @@ + array( + 'name' => 'rrze/fau-studium', + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => '8e00961c5f05620bc045007d2752fcae27e39b5a', + 'type' => 'wordpress-plugin', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => false, + ), + 'versions' => array( + 'inpsyde/assets' => array( + 'pretty_version' => '2.8.3', + 'version' => '2.8.3.0', + 'reference' => 'f198d7d8b726132851413a6a9b4918e02c077a4b', + 'type' => 'library', + 'install_path' => __DIR__ . '/../inpsyde/assets', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'inpsyde/modularity' => array( + 'pretty_version' => '1.8.0', + 'version' => '1.8.0.0', + 'reference' => 'c6855a6d9c4ce6f090d031e820f176bddf2a0b1c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../inpsyde/modularity', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'inpsyde/wp-context' => array( + 'pretty_version' => '1.5.0', + 'version' => '1.5.0.0', + 'reference' => '1f61ccb539e287e2688dfdf86dea0448c18fc8c6', + 'type' => 'library', + 'install_path' => __DIR__ . '/../inpsyde/wp-context', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/container' => array( + 'pretty_version' => '2.0.2', + 'version' => '2.0.2.0', + 'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/container', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/event-dispatcher' => array( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'reference' => 'dbefd12671e8a14ec7f180cab83036ed26714bb0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/event-dispatcher', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/log' => array( + 'pretty_version' => '3.0.0', + 'version' => '3.0.0.0', + 'reference' => 'fe5ea303b0887d5caefd3d431c3e61ad47037001', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/simple-cache' => array( + 'pretty_version' => '3.0.0', + 'version' => '3.0.0.0', + 'reference' => '764e0b3939f5ca87cb904f570ef9be2d78a07865', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/simple-cache', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'rrze/fau-studium' => array( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => '8e00961c5f05620bc045007d2752fcae27e39b5a', + 'type' => 'wordpress-plugin', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'rrze/fau-studium-common' => array( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => 'd8cb53c2cf24a6f28b07109cec9bb67c1d51d743', + 'type' => 'library', + 'install_path' => __DIR__ . '/../rrze/fau-studium-common', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'webmozart/assert' => array( + 'pretty_version' => '1.11.0', + 'version' => '1.11.0.0', + 'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991', + 'type' => 'library', + 'install_path' => __DIR__ . '/../webmozart/assert', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 000000000..adfb472fb --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 80000)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/inpsyde/assets/LICENSE b/vendor/inpsyde/assets/LICENSE new file mode 100644 index 000000000..1058d5d0d --- /dev/null +++ b/vendor/inpsyde/assets/LICENSE @@ -0,0 +1,361 @@ +### GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +### Preamble + +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the +original, so that any problems introduced by others will not reflect +on the original authors' reputations. + +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at +all. + +The precise terms and conditions for copying, distribution and +modification follow. + +### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +**0.** This License applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work +based on the Program" means either the Program or any derivative work +under copyright law: that is to say, a work containing the Program or +a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is +included without limitation in the term "modification".) Each licensee +is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether that +is true depends on what the Program does. + +**1.** You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a +fee. + +**2.** You may modify your copy or copies of the Program or any +portion of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + +**a)** You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + + +**b)** You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any part +thereof, to be licensed as a whole at no charge to all third parties +under the terms of this License. + + +**c)** If the modified program normally reads commands interactively +when run, you must cause it, when started running for such interactive +use in the most ordinary way, to print or display an announcement +including an appropriate copyright notice and a notice that there is +no warranty (or else, saying that you provide a warranty) and that +users may redistribute the program under these conditions, and telling +the user how to view a copy of this License. (Exception: if the +Program itself is interactive but does not normally print such an +announcement, your work based on the Program is not required to print +an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +**3.** You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + +**a)** Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange; or, + + +**b)** Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your cost of +physically performing source distribution, a complete machine-readable +copy of the corresponding source code, to be distributed under the +terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or, + + +**c)** Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is allowed +only for noncommercial distribution and only if you received the +program in object code or executable form with such an offer, in +accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +**4.** You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and +will automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. + +**5.** You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +**6.** Each time you redistribute the Program (or any work based on +the Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +**7.** If, as a consequence of a court judgment or allegation of +patent infringement or for any other reason (not limited to patent +issues), conditions are imposed on you (whether by court order, +agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. +If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, +then as a consequence you may not distribute the Program at all. For +example, if a patent license would not permit royalty-free +redistribution of the Program by all those who receive copies directly +or indirectly through you, then the only way you could satisfy both it +and this License would be to refrain entirely from distribution of the +Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +**8.** If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +**9.** The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation. + +**10.** If you wish to incorporate parts of the Program into other +free programs whose distribution conditions are different, write to +the author to ask for permission. For software which is copyrighted by +the Free Software Foundation, write to the Free Software Foundation; +we sometimes make exceptions for this. Our decision will be guided by +the two goals of preserving the free status of all derivatives of our +free software and of promoting the sharing and reuse of software +generally. + +**NO WARRANTY** + +**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +### END OF TERMS AND CONDITIONS + +### How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + one line to give the program's name and an idea of what it does. + Copyright (C) 2020 Inpsyde GmbH + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper +mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details + type `show w'. This is free software, and you are welcome + to redistribute it under certain conditions; type `show c' + for details. + +The hypothetical commands \`show w' and \`show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than \`show w' and +\`show c'; they could even be mouse-clicks or menu items--whatever +suits your program. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the program, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright + interest in the program `Gnomovision' + (which makes passes at compilers) written + by James Hacker. + + signature of Ty Coon, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, +you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +[GNU Lesser General Public +License](https://www.gnu.org/licenses/lgpl.html) instead of this +License. diff --git a/vendor/inpsyde/assets/composer.json b/vendor/inpsyde/assets/composer.json new file mode 100644 index 000000000..38a204986 --- /dev/null +++ b/vendor/inpsyde/assets/composer.json @@ -0,0 +1,73 @@ +{ + "name": "inpsyde/assets", + "description": "Package to manage assets in WordPress.", + "type": "library", + "license": "GPL-2.0-or-later", + "authors": [ + { + "name": "Inpsyde", + "email": "hello@inpsyde.com", + "homepage": "https://inpsyde.com", + "role": "Company" + }, + { + "name": "Christian Leucht", + "email": "c.leucht@inpsyde.com", + "homepage": "https://www.chrico.info", + "role": "Developer" + } + ], + "minimum-stability": "dev", + "prefer-stable": true, + "require": { + "php": ">=7.2", + "ext-json": "*", + "ext-dom": "*", + "inpsyde/wp-context": "^1.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.14 || ^9.0", + "brain/monkey": "^2.5.0", + "mikey179/vfsstream": "^1.6.8", + "inpsyde/php-coding-standards": "^1", + "vimeo/psalm": "@stable", + "php-stubs/wordpress-stubs": ">=6.0@stable", + "johnpbloch/wordpress-core": ">=6.0" + }, + "autoload": { + "psr-4": { + "Inpsyde\\Assets\\": "src/" + }, + "files": [ + "inc/functions.php", + "inc/bootstrap.php" + ] + }, + "autoload-dev": { + "psr-4": { + "Inpsyde\\Assets\\Tests\\Unit\\": "tests/phpunit/Unit/", + "Inpsyde\\Assets\\Tests\\Integration\\": "tests/phpunit/Integration/" + } + }, + "scripts": { + "cs": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs", + "psalm": "@php ./vendor/bin/psalm --output-format=compact --no-cache", + "tests": "@php ./vendor/phpunit/phpunit/phpunit", + "tests:no-cov": "@php ./vendor/phpunit/phpunit/phpunit --no-coverage", + "tests:codecov": "@php ./vendor/phpunit/phpunit/phpunit --coverage-clover coverage.xml", + "qa": [ + "@cs", + "@tests:no-cov" + ] + }, + "config": { + "optimize-autoloader": true, + "allow-plugins": { + "roots/wordpress-core-installer": true, + "dealerdirect/phpcodesniffer-composer-installer": true + } + }, + "extra": { + "wordpress-install-dir": "vendor/wordpress/wordpress" + } +} diff --git a/vendor/inpsyde/assets/inc/bootstrap.php b/vendor/inpsyde/assets/inc/bootstrap.php new file mode 100644 index 000000000..839aabea1 --- /dev/null +++ b/vendor/inpsyde/assets/inc/bootstrap.php @@ -0,0 +1,71 @@ +setup(); + + return $done; +} + +/* + * This file is loaded by Composer autoload, and that may happen before `add_action` is available. + * In that case, we first try to load `plugin.php` before calling `add_action`. + */ + +$addActionExists = function_exists('add_action'); +if ( + $addActionExists + || (defined('ABSPATH') && defined('WP_INC') && file_exists(ABSPATH . WP_INC . '/plugin.php')) +) { + if (!$addActionExists) { + require_once ABSPATH . WP_INC . '/plugin.php'; + } + + unset($addActionExists); + add_action('wp_loaded', __NAMESPACE__ . '\\bootstrap', 99); + + return; +} + +unset($addActionExists); + +/** + * If here, this file is loaded very early, probably too-much early, even before ABSPATH was defined + * so only option we have is to "manually" write in global `$wp_filter` array. + */ + +global $wp_filter; +is_array($wp_filter) or $wp_filter = []; +isset($wp_filter['wp_loaded']) or $wp_filter['wp_loaded'] = []; +isset($wp_filter['wp_loaded'][99]) or $wp_filter['wp_loaded'][99] = []; +$wp_filter['wp_loaded'][99][__NAMESPACE__ . '\\bootstrap'] = [ + 'function' => __NAMESPACE__ . '\\bootstrap', + 'accepted_args' => 0, +]; diff --git a/vendor/inpsyde/assets/inc/functions.php b/vendor/inpsyde/assets/inc/functions.php new file mode 100644 index 000000000..7d617ab43 --- /dev/null +++ b/vendor/inpsyde/assets/inc/functions.php @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/inpsyde/assets/src/Asset.php b/vendor/inpsyde/assets/src/Asset.php new file mode 100644 index 000000000..15cbb24e5 --- /dev/null +++ b/vendor/inpsyde/assets/src/Asset.php @@ -0,0 +1,198 @@ + + */ + public const HOOK_TO_LOCATION = [ + Asset::HOOK_FRONTEND => Asset::FRONTEND, + Asset::HOOK_BACKEND => Asset::BACKEND, + Asset::HOOK_LOGIN => Asset::LOGIN, + Asset::HOOK_CUSTOMIZER => Asset::CUSTOMIZER, + Asset::HOOK_CUSTOMIZER_PREVIEW => Asset::CUSTOMIZER_PREVIEW, + Asset::HOOK_BLOCK_ASSETS => Asset::BLOCK_ASSETS, + Asset::HOOK_BLOCK_EDITOR_ASSETS => Asset::BLOCK_EDITOR_ASSETS, + Asset::HOOK_ACTIVATE => Asset::ACTIVATE, + ]; + + /** + * Contains the full url to file. + * + * @return string + */ + public function url(): string; + + /** + * Returns the full file path to the asset. + * + * @return string + */ + public function filePath(): string; + + /** + * Define the full filePath to the Asset. + * + * @param string $filePath + * + * @return static + */ + public function withFilePath(string $filePath): Asset; + + /** + * Name of the given asset. + * + * @return string + */ + public function handle(): string; + + /** + * A list of handle-dependencies. + * + * @return string[] + */ + public function dependencies(): array; + + /** + * @param string ...$dependencies + * + * @return static + */ + public function withDependencies(string ...$dependencies): Asset; + + /** + * The current version of the asset. + * + * @return string|null + */ + public function version(): ?string; + + /** + * @param string $version + * + * @return static + */ + public function withVersion(string $version): Asset; + + /** + * @return bool + */ + public function enqueue(): bool; + + /** + * @param bool|callable $enqueue + * + * @return static + * + * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration.NoArgumentType + */ + public function canEnqueue($enqueue): Asset; + + /** + * Location where the asset is enqueued. + * + * @return int + * + * @example Asset::FRONTEND | Asset::BACKEND + * @example Asset::FRONTEND + */ + public function location(): int; + + /** + * Define a location based on Asset location types. + * + * @param int $location + * + * @return static + */ + public function forLocation(int $location): Asset; + + /** + * A list of assigned output filters to change the rendered tag. + * + * @return callable[]|AssetOutputFilter[]|class-string[] + */ + public function filters(): array; + + /** + * @param callable|class-string ...$filters + * + * @return static + */ + public function withFilters(...$filters): Asset; + + /** + * Name of the handler class to register and enqueue the asset. + * + * @return class-string + */ + public function handler(): string; + + /** + * @param class-string $handler + * + * @return static + */ + public function useHandler(string $handler): Asset; + + /** + * @return array + */ + public function data(): array; + + /** + * Add a conditional tag for your Asset. + * + * @param string $condition + * + * @return static + * + * @see https://developer.wordpress.org/reference/functions/wp_script_add_data/#comment-1007 + */ + public function withCondition(string $condition): Asset; + + /** + * @return array + */ + public function attributes(): array; + + /** + * @param array $attributes + * + * @return Asset + */ + public function withAttributes(array $attributes): Asset; +} diff --git a/vendor/inpsyde/assets/src/AssetFactory.php b/vendor/inpsyde/assets/src/AssetFactory.php new file mode 100644 index 000000000..1135f988a --- /dev/null +++ b/vendor/inpsyde/assets/src/AssetFactory.php @@ -0,0 +1,265 @@ + 'withFilePath', + 'version' => 'withVersion', + 'location' => 'forLocation', + 'enqueue' => 'canEnqueue', + 'handler' => 'useHandler', + 'condition' => 'withCondition', + 'attributes' => 'withAttributes', + ]; + + if ($asset instanceof Script) { + foreach ($config['localize'] as $objectName => $data) { + $asset->withLocalize((string) $objectName, $data); + } + + if (isset($config['translation'])) { + /** @var array{domain:string, path:?string} $translations */ + $translations = $config['translation']; + $asset->withTranslation( + (string) $translations['domain'], + $translations['path'] ?? null + ); + } + + $inFooter = $config['inFooter'] ?? true; + $inFooter + ? $asset->isInFooter() + : $asset->isInHeader(); + + if (!empty($config['inline']['before']) && is_array($config['inline']['before'])) { + foreach ($config['inline']['before'] as $script) { + $asset->prependInlineScript((string) $script); + } + } + + if (!empty($config['inline']['after']) && is_array($config['inline']['after'])) { + foreach ($config['inline']['after'] as $script) { + $asset->appendInlineScript((string) $script); + } + } + } + + if ($asset instanceof Style) { + $propertiesToMethod['media'] = 'forMedia'; + $propertiesToMethod['inlineStyles'] = 'withInlineStyles'; + $propertiesToMethod['media'] = 'forMedia'; + } + + foreach ($propertiesToMethod as $key => $methodName) { + if (!isset($config[$key])) { + continue; + } + $asset->{$methodName}($config[$key]); + } + + $dependencies = $config['dependencies'] ?? null; + if (is_array($dependencies)) { + $asset->withDependencies(...$dependencies); + } elseif (is_scalar($dependencies)) { + $asset->withDependencies((string) $dependencies); + } + + return $asset; + } + + /** + * @param array $config + * + * @return array + * + * @throws Exception\MissingArgumentException + */ + private static function validateConfig(array $config): array + { + self::ensureRequiredConfigFields($config); + $config = self::normalizeVersionConfig($config); + $config = self::normalizeTranslationConfig($config); + $config = self::normalizeLocalizeConfig($config); + + return $config; + } + + private static function ensureRequiredConfigFields(array $config): void + { + $requiredFields = [ + 'type', + 'url', + 'handle', + ]; + + foreach ($requiredFields as $key) { + if (!isset($config[$key])) { + throw new Exception\MissingArgumentException( + sprintf( + 'The given config %s is missing.', + $key + ) + ); + } + } + } + + private static function normalizeVersionConfig(array $config): array + { + // some existing configurations uses time() as version parameter which leads to + // fatal errors since 2.5 + if (isset($config['version'])) { + $config['version'] = (string) $config['version']; + } + + return $config; + } + + private static function normalizeTranslationConfig(array $config): array + { + if (!isset($config['translation'])) { + return $config; + } + + if (is_string($config['translation'])) { + // backward compatibility + $config['translation'] = [ + 'domain' => $config['translation'], + 'path' => null, + ]; + + return $config; + } + + if (!is_array($config['translation'])) { + throw new InvalidArgumentException( + "Config key translation must be of type string or array" + ); + } + + if (!isset($config['translation']['domain'])) { + throw new Exception\MissingArgumentException( + 'Config key translation[domain] is missing.' + ); + } + + if (!isset($config['translation']['path'])) { + $config['translation']['path'] = null; + } + + return $config; + } + + private static function normalizeLocalizeConfig(array $config): array + { + if (!isset($config['localize'])) { + $config['localize'] = []; + + return $config; + } + if (is_callable($config['localize'])) { + $config['localize'] = $config['localize'](); + } + if (!is_array($config['localize'])) { + throw new InvalidArgumentException( + 'Config key localize must evaluate as an array' + ); + } + + return $config; + } + + /** + * @param string $file + * + * @return array + * + * @throws Exception\FileNotFoundException + * @deprecated PhpArrayFileLoader::load(string $filePath) + * + */ + public static function createFromFile(string $file): array + { + $loader = new PhpFileLoader(); + + return $loader->load($file); + } + + /** + * @param array $data + * + * @return array + * + * @throws Exception\FileNotFoundException + * @deprecated ArrayLoader::load(array $data) + */ + public static function createFromArray(array $data): array + { + $loader = new ArrayLoader(); + + return $loader->load($data); + } +} diff --git a/vendor/inpsyde/assets/src/AssetManager.php b/vendor/inpsyde/assets/src/AssetManager.php new file mode 100644 index 000000000..4841dd632 --- /dev/null +++ b/vendor/inpsyde/assets/src/AssetManager.php @@ -0,0 +1,320 @@ + + */ + private $hooksAdded = []; + + /** + * @var \SplObjectStorage + */ + private $assets; + + /** + * @var array + */ + private $handlers = []; + + /** + * @var AssetHookResolver + */ + private $hookResolver; + + /** + * @var bool + */ + private $setupDone = false; + + /** + * @param AssetHookResolver|null $hookResolver + */ + public function __construct(AssetHookResolver $hookResolver = null) + { + $this->hookResolver = $hookResolver ?? new AssetHookResolver(); + $this->assets = new \SplObjectStorage(); + } + + /** + * @return static + */ + public function useDefaultHandlers(): AssetManager + { + empty($this->handlers[StyleHandler::class]) + and $this->handlers[StyleHandler::class] = new StyleHandler(wp_styles()); + + empty($this->handlers[ScriptHandler::class]) + and $this->handlers[ScriptHandler::class] = new ScriptHandler(wp_scripts()); + + return $this; + } + + /** + * @param string $name + * @param AssetHandler $handler + * + * @return static + */ + public function withHandler(string $name, AssetHandler $handler): AssetManager + { + $this->handlers[$name] = $handler; + + return $this; + } + + /** + * @return array + */ + public function handlers(): array + { + return $this->handlers; + } + + /** + * @param Asset $asset + * @param Asset ...$assets + * + * @return static + */ + public function register(Asset $asset, Asset ...$assets): AssetManager + { + array_unshift($assets, $asset); + + foreach ($assets as $asset) { + $handle = $asset->handle(); + if ($handle) { + $this->assets->attach($asset, [$handle, get_class($asset)]); + } + } + + return $this; + } + + /** + * @return array> + */ + public function assets(): array + { + $this->ensureSetup(); + + $found = []; + $this->assets->rewind(); + while ($this->assets->valid()) { + $asset = $this->assets->current(); + [$handle, $class] = $this->assets->getInfo(); + isset($found[$class]) or $found[$class] = []; + $found[$class][$handle] = $asset; + + $this->assets->next(); + } + + return $found; + } + + /** + * Retrieve an `Asset` instance by a given asset handle and type (class). + * + * If the handle is unique by type, type can be omitted. + * It is possible to use a parent class as type. + * E.g an asset of a type `MyScript` that extends `Script` can be also retrieved passing + * either `MyScript or `Script` as type. + * + * @param string $handle + * @param class-string|null $type + * + * @return Asset|null + */ + public function asset(string $handle, ?string $type = null): ?Asset + { + $this->ensureSetup(); + + /** @var Asset|null $found */ + $found = null; + $this->assets->rewind(); + + while ($this->assets->valid()) { + $asset = $this->assets->current(); + $this->assets->next(); + + if (($asset->handle() !== $handle) || ($type && !is_a($asset, $type))) { + continue; + } + + if ($found) { + // only one asset can match + return null; + } + + $found = $asset; + } + + return $found; + } + + /** + * @return bool + */ + public function setup(): bool + { + $hooksAdded = 0; + + /** + * It is possible to execute AssetManager::setup() at a specific hook to only process assets + * specific of that hook. + * + * E.g. `add_action('enqueue_block_editor_assets', [new AssetManager, 'setup']);` + * + * `$this->hookResolver->resolve()` will return current hook if it is one of the assets + * enqueuing hook. + */ + foreach ($this->hookResolver->resolve() as $hook) { + // If the hook was already added, or it is in the past, don't bother adding. + if (!empty($this->hooksAdded[$hook]) || (did_action($hook) && !doing_action($hook))) { + continue; + } + + $hooksAdded++; + $this->hooksAdded[$hook] = true; + + add_action( + $hook, + function () use ($hook) { + $this->processAssets($hook); + } + ); + } + + return $hooksAdded > 0; + } + + /** + * Returning all matching assets to given hook. + * + * @param string $currentHook + * + * @return array + */ + public function currentAssets(string $currentHook): array + { + return $this->loopCurrentHookAssets($currentHook, false); + } + + /** + * @param string $currentHook + * + * @return void + */ + private function processAssets(string $currentHook): void + { + $this->loopCurrentHookAssets($currentHook, true); + } + + /** + * @param string $currentHook + * @param bool $process + * + * @return array + * + * phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh + */ + private function loopCurrentHookAssets(string $currentHook, bool $process): array + { + $this->ensureSetup(); + if (!$this->assets->count()) { + return []; + } + + /** @var int|null $locationId */ + $locationId = Asset::HOOK_TO_LOCATION[$currentHook] ?? null; + if (!$locationId) { + return []; + } + + $found = []; + + $this->assets->rewind(); + while ($this->assets->valid()) { + $asset = $this->assets->current(); + $this->assets->next(); + + $handlerName = $asset->handler(); + $handler = $this->handlers[$handlerName] ?? null; + if (!$handler) { + continue; + } + + $location = $asset->location(); + if (($location & $locationId) !== $locationId) { + continue; + } + + $found[] = $asset; + if (!$process) { + continue; + } + + $done = $asset->enqueue() + ? $handler->enqueue($asset) + : $handler->register($asset); + if ($done && ($handler instanceof OutputFilterAwareAssetHandler)) { + $handler->filter($asset); + } + } + + return $found; + } + + /** + * @return void + */ + private function ensureSetup(): void + { + if ($this->setupDone) { + return; + } + + $this->setupDone = true; + + $lastHook = $this->hookResolver->lastHook(); + + /** + * We should not setup if there's no hook or last hook already fired. + * + * @psalm-suppress PossiblyNullArgument + */ + if (!$lastHook && did_action($lastHook) && !doing_action($lastHook)) { + $this->assets = new \SplObjectStorage(); + + return; + } + + $this->useDefaultHandlers(); + do_action(self::ACTION_SETUP, $this); + } +} diff --git a/vendor/inpsyde/assets/src/BaseAsset.php b/vendor/inpsyde/assets/src/BaseAsset.php new file mode 100644 index 000000000..01a8e50dc --- /dev/null +++ b/vendor/inpsyde/assets/src/BaseAsset.php @@ -0,0 +1,400 @@ +[] + */ + protected $filters = []; + + /** + * @var class-string|null + */ + protected $handler = null; + + /** + * Data which will be added via ... + * - WP_Script::add_data() + * - WP_Style::add_data() + * + * @var array + */ + protected $data = []; + + /** + * Additional attributes to "link"- or "script"-tag. + * + * @var array + */ + protected $attributes = []; + + /** + * @param string $handle + * @param string $url + * @param int $location + */ + public function __construct( + string $handle, + string $url, + int $location = Asset::FRONTEND | Asset::ACTIVATE + ) { + + $this->handle = $handle; + $this->url = $url; + $this->location = $location; + } + + /** + * @return string + */ + public function url(): string + { + return $this->url; + } + + /** + * @return string + */ + public function handle(): string + { + return $this->handle; + } + + /** + * @return string + */ + public function filePath(): string + { + $filePath = $this->filePath; + + if ($filePath !== '') { + return $filePath; + } + + try { + $filePath = AssetPathResolver::resolve($this->url()); + } catch (\Throwable $throwable) { + $filePath = null; + } + + // if replacement fails, don't set the url as path. + if ($filePath === null || !file_exists($filePath)) { + return ''; + } + + $this->withFilePath($filePath); + + return $filePath; + } + + /** + * @param string $filePath + * + * @return static + */ + public function withFilePath(string $filePath): Asset + { + $this->filePath = $filePath; + + return $this; + } + + /** + * Returns a version which will be automatically generated based on file time by default. + * + * @return string|null + */ + public function version(): ?string + { + $version = $this->version; + + if ($version === null && $this->autodiscoverVersion) { + $filePath = $this->filePath(); + $version = (string) filemtime($filePath); + $this->withVersion($version); + + return $version; + } + + return $version === null + ? null + : (string) $version; + } + + /** + * @param string $version + * + * @return static + */ + public function withVersion(string $version): Asset + { + $this->version = $version; + + return $this; + } + + /** + * @return string[] + */ + public function dependencies(): array + { + return array_values(array_unique($this->dependencies)); + } + + /** + * @param string ...$dependencies + * + * @return static + */ + public function withDependencies(string ...$dependencies): Asset + { + $this->dependencies = array_merge( + $this->dependencies, + $dependencies + ); + + return $this; + } + + /** + * @return int + */ + public function location(): int + { + return (int) $this->location; + } + + /** + * @param int $location + * + * @return static + */ + public function forLocation(int $location): Asset + { + $this->location = $location; + + return $this; + } + + /** + * @return callable[]|AssetOutputFilter[]|class-string[] + */ + public function filters(): array + { + return $this->filters; + } + + /** + * @param callable|class-string ...$filters + * + * @return static + * + * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration + */ + public function withFilters(...$filters): Asset + { + $this->filters = array_merge($this->filters, $filters); + + return $this; + } + + /** + * Shortcut to use the InlineFilter. + * + * @return static + */ + public function useInlineFilter(): Asset + { + $this->withFilters(InlineAssetOutputFilter::class); + + return $this; + } + + /** + * @return bool + */ + public function enqueue(): bool + { + $enqueue = $this->enqueue; + is_callable($enqueue) and $enqueue = $enqueue(); + + return (bool) $enqueue; + } + + /** + * @param bool|callable(): bool $enqueue + * + * @return static + * + * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration + * @psalm-suppress MoreSpecificImplementedParamType + */ + public function canEnqueue($enqueue): Asset + { + // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration + + $this->enqueue = $enqueue; + + return $this; + } + + /** + * @param class-string $handler + * + * @return static + */ + public function useHandler(string $handler): Asset + { + $this->handler = $handler; + + return $this; + } + + /** + * @return class-string + */ + public function handler(): string + { + if (!$this->handler) { + $this->handler = $this->defaultHandler(); + } + + return $this->handler; + } + + /** + * @return class-string className of the default handler + */ + abstract protected function defaultHandler(): string; + + /** + * @return array + */ + public function data(): array + { + return $this->data; + } + + /** + * Allows to set additional data via WP_Script::add_data() or WP_Style::add_data(). + * + * @param array $data + * + * @return static + */ + public function withData(array $data): Asset + { + $this->data = array_merge($this->data, $data); + + return $this; + } + + /** + * Shortcut for Asset::withData(['conditional' => $condition]); + * + * @param string $condition + * + * @return static + */ + public function withCondition(string $condition): Asset + { + $this->withData(['conditional' => $condition]); + + return $this; + } + + /** + * @return array + */ + public function attributes(): array + { + return $this->attributes; + } + + /** + * Allows you to set additional attributes to your "link"- or "script"-tag. + * Existing attributes like "src" or "id" will not be overwrite. + * + * @param array $attributes + * + * @return static + */ + public function withAttributes(array $attributes): Asset + { + $this->attributes = array_merge($this->attributes, $attributes); + $this->withFilters(AttributesOutputFilter::class); + + return $this; + } +} diff --git a/vendor/inpsyde/assets/src/ConfigureAutodiscoverVersionTrait.php b/vendor/inpsyde/assets/src/ConfigureAutodiscoverVersionTrait.php new file mode 100644 index 000000000..a5da49d00 --- /dev/null +++ b/vendor/inpsyde/assets/src/ConfigureAutodiscoverVersionTrait.php @@ -0,0 +1,59 @@ +autodiscoverVersion = true; + + return $this; + } + + /** + * Disable automatic discovering of the version if no version is set. + * + * @return static + * + * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + */ + public function disableAutodiscoverVersion() + { + // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration + + $this->autodiscoverVersion = false; + + return $this; + } +} diff --git a/vendor/inpsyde/assets/src/Exception/FileNotFoundException.php b/vendor/inpsyde/assets/src/Exception/FileNotFoundException.php new file mode 100644 index 000000000..7bdd258ab --- /dev/null +++ b/vendor/inpsyde/assets/src/Exception/FileNotFoundException.php @@ -0,0 +1,18 @@ +> + */ + public function outputFilters(): array; +} diff --git a/vendor/inpsyde/assets/src/Handler/OutputFilterAwareAssetHandlerTrait.php b/vendor/inpsyde/assets/src/Handler/OutputFilterAwareAssetHandlerTrait.php new file mode 100644 index 000000000..8a6f10f28 --- /dev/null +++ b/vendor/inpsyde/assets/src/Handler/OutputFilterAwareAssetHandlerTrait.php @@ -0,0 +1,102 @@ +> + */ + protected $outputFilters = []; + + /** + * @param string $name + * @param callable $filter + * + * @return OutputFilterAwareAssetHandler + */ + public function withOutputFilter(string $name, callable $filter): OutputFilterAwareAssetHandler + { + $this->outputFilters[$name] = $filter; + + return $this; + } + + /** + * @return array> + */ + public function outputFilters(): array + { + return $this->outputFilters; + } + + /** + * @param Asset $asset + * + * @return bool + */ + public function filter(Asset $asset): bool + { + $filters = $this->currentOutputFilters($asset); + if (count($filters) === 0) { + return false; + } + + add_filter( + $this->filterHook(), + static function (string $html, string $handle) use ($filters, $asset): string { + if ($handle !== $asset->handle()) { + return $html; + } + foreach ($filters as $filter) { + /** @psalm-suppress MixedFunctionCall */ + $html = (string) $filter($html, $asset); + } + + return $html; + }, + 10, + 2 + ); + + return true; + } + + protected function currentOutputFilters(Asset $asset): array + { + $filters = []; + $registeredFilters = $this->outputFilters(); + foreach ($asset->filters() as $filter) { + if (is_callable($filter)) { + $filters[] = $filter; + continue; + } + if (isset($registeredFilters[$filter])) { + $filters[] = $registeredFilters[$filter]; + } + } + + return $filters; + } + + /** + * Defines the name of hook to filter the specific asset. + * + * @return string + */ + abstract public function filterHook(): string; +} diff --git a/vendor/inpsyde/assets/src/Handler/ScriptHandler.php b/vendor/inpsyde/assets/src/Handler/ScriptHandler.php new file mode 100644 index 000000000..056ee7668 --- /dev/null +++ b/vendor/inpsyde/assets/src/Handler/ScriptHandler.php @@ -0,0 +1,119 @@ + $outputFilters + */ + public function __construct(WP_Scripts $wpScripts, array $outputFilters = []) + { + $this->withOutputFilter(AsyncScriptOutputFilter::class, new AsyncScriptOutputFilter()); + $this->withOutputFilter(DeferScriptOutputFilter::class, new DeferScriptOutputFilter()); + $this->withOutputFilter(InlineAssetOutputFilter::class, new InlineAssetOutputFilter()); + $this->withOutputFilter(AttributesOutputFilter::class, new AttributesOutputFilter()); + + $this->wpScripts = $wpScripts; + foreach ($outputFilters as $name => $callable) { + $this->withOutputFilter($name, $callable); + } + } + + public function enqueue(Asset $asset): bool + { + $this->register($asset); + + if ($asset->enqueue()) { + wp_enqueue_script($asset->handle()); + + return true; + } + + return false; + } + + public function register(Asset $asset): bool + { + /** @var Script $asset */ + + $handle = $asset->handle(); + + wp_register_script( + $handle, + $asset->url(), + $asset->dependencies(), + $asset->version(), + $asset->inFooter() + ); + + if (count($asset->localize()) > 0) { + foreach ($asset->localize() as $name => $args) { + /** + * Actually it is possible to use $args as scalar value for + * \WP_Scripts::localize() - but it will produce a _doing_it_wrong(). + * + * @psalm-suppress MixedArgument + */ + wp_localize_script($handle, $name, $args); + } + } + + foreach ($asset->inlineScripts() as $location => $data) { + if (count($data) > 0) { + wp_add_inline_script($handle, implode("\n", $data), $location); + } + } + + $translation = $asset->translation(); + if ($translation['domain'] !== '') { + /** + * The $path is allowed to be "null"- or a "string"-value. + * @psalm-suppress PossiblyNullArgument + */ + wp_set_script_translations($handle, $translation['domain'], $translation['path']); + } + + if (count($asset->data()) > 0) { + foreach ($asset->data() as $key => $value) { + $this->wpScripts->add_data($handle, $key, $value); + } + } + + return true; + } + + public function filterHook(): string + { + return 'script_loader_tag'; + } +} diff --git a/vendor/inpsyde/assets/src/Handler/StyleHandler.php b/vendor/inpsyde/assets/src/Handler/StyleHandler.php new file mode 100644 index 000000000..e7ea3d517 --- /dev/null +++ b/vendor/inpsyde/assets/src/Handler/StyleHandler.php @@ -0,0 +1,98 @@ + $outputFilters + */ + public function __construct(\WP_Styles $wpStyles, array $outputFilters = []) + { + $this->withOutputFilter(AsyncStyleOutputFilter::class, new AsyncStyleOutputFilter()); + $this->withOutputFilter(InlineAssetOutputFilter::class, new InlineAssetOutputFilter()); + $this->withOutputFilter(AttributesOutputFilter::class, new AttributesOutputFilter()); + + $this->wpStyles = $wpStyles; + foreach ($outputFilters as $name => $callable) { + $this->withOutputFilter($name, $callable); + } + } + + public function enqueue(Asset $asset): bool + { + $this->register($asset); + + if ($asset->enqueue()) { + wp_enqueue_style($asset->handle()); + + return true; + } + + return false; + } + + public function register(Asset $asset): bool + { + /** @var Style $asset */ + + $handle = $asset->handle(); + wp_register_style( + $handle, + $asset->url(), + $asset->dependencies(), + $asset->version(), + $asset->media() + ); + + $inlineStyles = $asset->inlineStyles(); + if ($inlineStyles !== null) { + wp_add_inline_style($handle, implode("\n", $inlineStyles)); + } + + $cssVars = $asset->cssVars(); + if (count($cssVars) > 0) { + wp_add_inline_style($handle, $asset->cssVarsAsString()); + } + + if (count($asset->data()) > 0) { + foreach ($asset->data() as $key => $value) { + $this->wpStyles->add_data($handle, $key, $value); + } + } + + return true; + } + + public function filterHook(): string + { + return 'style_loader_tag'; + } +} diff --git a/vendor/inpsyde/assets/src/Loader/AbstractWebpackLoader.php b/vendor/inpsyde/assets/src/Loader/AbstractWebpackLoader.php new file mode 100644 index 000000000..a8f965579 --- /dev/null +++ b/vendor/inpsyde/assets/src/Loader/AbstractWebpackLoader.php @@ -0,0 +1,208 @@ +directoryUrl = $directoryUrl; + + return $this; + } + + /** + * @param array $data + * @param string $resource + * + * @return array + */ + abstract protected function parseData(array $data, string $resource): array; + + /** + * @param mixed $resource + * + * @return array + * + * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration + * @psalm-suppress MixedArgument + */ + public function load($resource): array + { + if (!is_string($resource) || !is_readable($resource)) { + throw new FileNotFoundException( + sprintf( + 'The given file "%s" does not exists or is not readable.', + (string) $resource + ) + ); + } + + $data = @file_get_contents($resource) + ?: ''; // phpcs:ignore + $data = json_decode($data, true); + $errorCode = json_last_error(); + if (0 < $errorCode) { + throw new InvalidResourceException( + sprintf('Error parsing JSON - %s', $this->getJSONErrorMessage($errorCode)) + ); + } + + return $this->parseData($data, $resource); + } + + /** + * Translates JSON_ERROR_* constant into meaningful message. + * + * @param int $errorCode + * + * @return string Message string + */ + private function getJSONErrorMessage(int $errorCode): string + { + switch ($errorCode) { + case JSON_ERROR_DEPTH: + return 'Maximum stack depth exceeded'; + case JSON_ERROR_STATE_MISMATCH: + return 'Underflow or the modes mismatch'; + case JSON_ERROR_CTRL_CHAR: + return 'Unexpected control character found'; + case JSON_ERROR_SYNTAX: + return 'Syntax error, malformed JSON'; + case JSON_ERROR_UTF8: + return 'Malformed UTF-8 characters, possibly incorrectly encoded'; + default: + return 'Unknown error'; + } + } + + /** + * @param string $handle + * @param string $fileUrl + * @param string $filePath + * + * @return Asset|null + */ + protected function buildAsset(string $handle, string $fileUrl, string $filePath): ?Asset + { + $extensionsToClass = [ + 'css' => Style::class, + 'js' => Script::class, + ]; + + /** @var array{filename?:string, extension?:string} $pathInfo */ + $pathInfo = pathinfo($filePath); + $filename = $pathInfo['filename'] ?? ''; + $extension = $pathInfo['extension'] ?? ''; + + if (!in_array($extension, array_keys($extensionsToClass), true)) { + return null; + } + + $class = $extensionsToClass[$extension]; + + /** @var Asset|BaseAsset $asset */ + $asset = new $class($handle, $fileUrl, $this->resolveLocation($filename)); + $asset->withFilePath($filePath); + $asset->canEnqueue(true); + + if ($asset instanceof BaseAsset) { + $this->autodiscoverVersion + ? $asset->enableAutodiscoverVersion() + : $asset->disableAutodiscoverVersion(); + } + + return $asset; + } + + /** + * The "file"-value can contain: + * - URL + * - Path to current folder + * - Absolute path + * + * We try to build a clean path which will be appended to the directoryPath or urlPath. + * + * @param string $file + * + * @return string + */ + protected function sanitizeFileName(string $file): string + { + // Check, if the given "file"-value is an URL + $parsedUrl = parse_url($file); + + // the "file"-value can contain "./file.css" or "/file.css". + + return ltrim($parsedUrl['path'] ?? $file, './'); + } + + /** + * Internal function to resolve a location for a given file name. + * + * @param string $fileName + * + * @return int + * + * @example foo-customizer.css -> Asset::CUSTOMIZER + * @example foo-block.css -> Asset::BLOCK_EDITOR_ASSETS + * @example foo-login.css -> Asset::LOGIN + * @example foo.css -> Asset::FRONTEND + * @example foo-backend.css -> Asset::BACKEND + */ + protected function resolveLocation(string $fileName): int + { + if (stristr($fileName, '-backend')) { + return Asset::BACKEND; + } + + if (stristr($fileName, '-block')) { + return Asset::BLOCK_EDITOR_ASSETS; + } + + if (stristr($fileName, '-login')) { + return Asset::LOGIN; + } + + if (stristr($fileName, '-customizer-preview')) { + return Asset::CUSTOMIZER_PREVIEW; + } + + if (stristr($fileName, '-customizer')) { + return Asset::CUSTOMIZER; + } + + return Asset::FRONTEND; + } +} diff --git a/vendor/inpsyde/assets/src/Loader/ArrayLoader.php b/vendor/inpsyde/assets/src/Loader/ArrayLoader.php new file mode 100644 index 000000000..2ff5429fa --- /dev/null +++ b/vendor/inpsyde/assets/src/Loader/ArrayLoader.php @@ -0,0 +1,55 @@ +autodiscoverVersion + ? $asset->enableAutodiscoverVersion() + : $asset->disableAutodiscoverVersion(); + } + return $asset; + }, + $assets + ); + } +} diff --git a/vendor/inpsyde/assets/src/Loader/EncoreEntrypointsLoader.php b/vendor/inpsyde/assets/src/Loader/EncoreEntrypointsLoader.php new file mode 100644 index 000000000..f87f482a6 --- /dev/null +++ b/vendor/inpsyde/assets/src/Loader/EncoreEntrypointsLoader.php @@ -0,0 +1,90 @@ + $filesByExtension) { + $files = $filesByExtension['css'] ?? []; + $assets = array_merge($assets, $this->extractAssets($handle, $files, $directory)); + + $files = $filesByExtension['js'] ?? []; + $assets = array_merge($assets, $this->extractAssets($handle, $files, $directory)); + } + + return $assets; + } + + /** + * @param string $handle + * @param string[] $files + * @param string $directory + * + * @return array + */ + protected function extractAssets(string $handle, array $files, string $directory): array + { + $assets = []; + + foreach ($files as $i => $file) { + $handle = $i > 0 + ? "{$handle}-{$i}" + : $handle; + + $sanitizedFile = $this->sanitizeFileName($file); + + $fileUrl = (!$this->directoryUrl) + ? $file + : $this->directoryUrl . $sanitizedFile; + + $filePath = $directory . $sanitizedFile; + + $asset = $this->buildAsset($handle, $fileUrl, $filePath); + + if ($asset !== null) { + $assets[] = $asset; + } + } + + foreach ($assets as $i => $asset) { + $dependencies = array_map( + static function (Asset $asset): string { + return $asset->handle(); + }, + array_slice($assets, 0, $i) + ); + $asset->withDependencies(...$dependencies); + } + + return $assets; + } +} diff --git a/vendor/inpsyde/assets/src/Loader/LoaderInterface.php b/vendor/inpsyde/assets/src/Loader/LoaderInterface.php new file mode 100644 index 000000000..7f3436b36 --- /dev/null +++ b/vendor/inpsyde/assets/src/Loader/LoaderInterface.php @@ -0,0 +1,22 @@ + $file) { + // It can be possible, that the "handle"-key is a filepath. + $handle = pathinfo($handle, PATHINFO_FILENAME); + + $sanitizedFile = $this->sanitizeFileName($file); + + $fileUrl = (! $this->directoryUrl) + ? $file + : $this->directoryUrl . $sanitizedFile; + + $filePath = $directory . $sanitizedFile; + + $asset = $this->buildAsset($handle, $fileUrl, $filePath); + if ($asset !== null) { + $assets[] = $asset; + } + } + + return $assets; + } +} diff --git a/vendor/inpsyde/assets/src/OutputFilter/AssetOutputFilter.php b/vendor/inpsyde/assets/src/OutputFilter/AssetOutputFilter.php new file mode 100644 index 000000000..c8add76f9 --- /dev/null +++ b/vendor/inpsyde/assets/src/OutputFilter/AssetOutputFilter.php @@ -0,0 +1,25 @@ + true']); + */ +class AsyncScriptOutputFilter implements AssetOutputFilter +{ + public function __invoke(string $html, Asset $asset): string + { + return str_replace('"; + $this->polyfillPrinted = true; + } + + return $output; + } +} diff --git a/vendor/inpsyde/assets/src/OutputFilter/AttributesOutputFilter.php b/vendor/inpsyde/assets/src/OutputFilter/AttributesOutputFilter.php new file mode 100644 index 000000000..8aec88760 --- /dev/null +++ b/vendor/inpsyde/assets/src/OutputFilter/AttributesOutputFilter.php @@ -0,0 +1,119 @@ +'; + private const ROOT_ELEMENT_END = ''; + + /** + * @param string $html + * @param Asset $asset + * + * @return string + * + * phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged + * @psalm-suppress PossiblyFalseArgument + * @psalm-suppress ArgumentTypeCoercion + */ + public function __invoke(string $html, Asset $asset): string + { + $attributes = $asset->attributes(); + if (count($attributes) === 0) { + return $html; + } + + $html = $this->wrapHtmlIntoRoot($html); + + $doc = new \DOMDocument(); + libxml_use_internal_errors(true); + @$doc->loadHTML( + mb_convert_encoding($html, 'HTML-ENTITIES', "UTF-8"), + LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD + ); + libxml_clear_errors(); + + $scripts = $doc->getElementsByTagName('script'); + foreach ($scripts as $script) { + // Only extend before and after. + if (!$script->hasAttribute('src')) { + continue; + } + $this->applyAttributes($script, $attributes); + } + + return $this->removeRootElement($doc->saveHTML()); + } + + /** + * Wrapping multiple scripts into a root-element + * to be able to load it via DOMDocument. + * + * @param string $html + * + * @return string + */ + protected function wrapHtmlIntoRoot(string $html): string + { + return self::ROOT_ELEMENT_START . $html . self::ROOT_ELEMENT_END; + } + + /** + * Remove root element and return original HTML. + * + * @param string $html + * + * @return string + * @see AttributesOutputFilter::wrapHtmlIntoRoot() + * + */ + protected function removeRootElement(string $html): string + { + $regex = '~' . self::ROOT_ELEMENT_START . '(.+?)' . self::ROOT_ELEMENT_END . '~s'; + preg_match($regex, $html, $matches); + + return $matches[1]; + } + + /** + * @param \DOMElement $script + * @param array $attributes + * + * @return void + */ + protected function applyAttributes(\DOMElement $script, array $attributes) + { + foreach ($attributes as $key => $value) { + $key = esc_attr((string) $key); + if ($script->hasAttribute($key)) { + continue; + } + if (is_bool($value) && !$value) { + continue; + } + $value = is_bool($value) + ? esc_attr($key) + : esc_attr((string) $value); + + $script->setAttribute($key, $value); + } + } +} diff --git a/vendor/inpsyde/assets/src/OutputFilter/DeferScriptOutputFilter.php b/vendor/inpsyde/assets/src/OutputFilter/DeferScriptOutputFilter.php new file mode 100644 index 000000000..9360a2fd2 --- /dev/null +++ b/vendor/inpsyde/assets/src/OutputFilter/DeferScriptOutputFilter.php @@ -0,0 +1,27 @@ + true']); + */ +class DeferScriptOutputFilter implements AssetOutputFilter +{ + public function __invoke(string $html, Asset $asset): string + { + return str_replace('', + $asset->version(), + $asset->handle(), + $content + ); + } + + if ($asset instanceof Style) { + return sprintf( + '', + $asset->version(), + $asset->handle(), + $content + ); + } + + return $html; + } +} diff --git a/vendor/inpsyde/assets/src/Script.php b/vendor/inpsyde/assets/src/Script.php new file mode 100644 index 000000000..44a8b8b1c --- /dev/null +++ b/vendor/inpsyde/assets/src/Script.php @@ -0,0 +1,318 @@ + + */ + protected $localize = []; + + /** + * @var array{after:string[], before:string[]} + */ + protected $inlineScripts = [ + 'after' => [], + 'before' => [], + ]; + + /** + * @var bool + */ + protected $inFooter = true; + + /** + * @var array{domain:string, path:string|null} + */ + protected $translation = [ + 'domain' => '', + 'path' => null, + ]; + + /** + * @var bool + */ + protected $resolvedDependencyExtractionPlugin = false; + + /** + * @return array + */ + public function localize(): array + { + $output = []; + foreach ($this->localize as $objectName => $data) { + $output[$objectName] = is_callable($data) + ? $data() + : $data; + } + + return $output; + } + + /** + * @param string $objectName + * @param string|int|array|callable $data + * + * @return static + * + * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration + */ + public function withLocalize(string $objectName, $data): Script + { + // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration + + $this->localize[$objectName] = $data; + + return $this; + } + + /** + * @return bool + */ + public function inFooter(): bool + { + return $this->inFooter; + } + + /** + * @return static + */ + public function isInFooter(): Script + { + $this->inFooter = true; + + return $this; + } + + /** + * @return static + */ + public function isInHeader(): Script + { + $this->inFooter = false; + + return $this; + } + + /** + * @return array{before:string[], after:string[]} + */ + public function inlineScripts(): array + { + return $this->inlineScripts; + } + + /** + * @param string $jsCode + * + * @return static + */ + public function prependInlineScript(string $jsCode): Script + { + $this->inlineScripts['before'][] = $jsCode; + + return $this; + } + + /** + * @param string $jsCode + * + * @return static + */ + public function appendInlineScript(string $jsCode): Script + { + $this->inlineScripts['after'][] = $jsCode; + + return $this; + } + + /** + * @return array{domain:string, path:string|null} + */ + public function translation(): array + { + return $this->translation; + } + + /** + * @param string $domain + * @param string|null $path + * + * @return static + */ + public function withTranslation(string $domain = 'default', string $path = null): Script + { + $this->translation = ['domain' => $domain, 'path' => $path]; + + return $this; + } + + /** + * Wrapper function to set AsyncScriptOutputFilter as filter. + * + * @return static + * @deprecated use Script::withAttributes(['async' => true]); + */ + public function useAsyncFilter(): Script + { + $this->withAttributes(['async' => true]); + + return $this; + } + + /** + * Wrapper function to set DeferScriptOutputFilter as filter. + * + * @return static + * @deprecated use Script::withAttributes(['defer' => true]); + */ + public function useDeferFilter(): Script + { + $this->withAttributes(['defer' => true]); + + return $this; + } + + /** + * {@inheritDoc} + */ + protected function defaultHandler(): string + { + return ScriptHandler::class; + } + + /** + * @deprecated when calling Script::version() or Script::dependencies(), + * we will automatically resolve the dependency extraction plugin files. + * This method will be removed in future. + * + * @see https://github.com/WordPress/gutenberg/tree/master/packages/dependency-extraction-webpack-plugin + */ + public function useDependencyExtractionPlugin(): Script + { + return $this; + } + + /** + * {@inheritDoc} + */ + public function version(): ?string + { + $this->resolveDependencyExtractionPlugin(); + + return parent::version(); + } + + /** + * {@inheritDoc} + */ + public function dependencies(): array + { + $this->resolveDependencyExtractionPlugin(); + + return parent::dependencies(); + } + + /** + * @return bool + * + * phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged + * phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable + * @psalm-suppress MixedArrayAccess + * @psalm-suppress PossiblyFalseArgument + * @psalm-suppress UnresolvableInclude + */ + protected function resolveDependencyExtractionPlugin(): bool + { + if ($this->resolvedDependencyExtractionPlugin) { + return false; + } + $this->resolvedDependencyExtractionPlugin = true; + + $depsFile = $this->findDepdendencyFile(); + if (!$depsFile) { + return false; + } + + $depsFilePath = $depsFile->getPathname(); + $data = $depsFile->getExtension() === 'json' + ? @json_decode(@file_get_contents($depsFilePath), true) + : @require $depsFilePath; + + /** @var string[] $dependencies */ + $dependencies = $data['dependencies'] ?? []; + /** @var string|null $version */ + $version = $data['version'] ?? null; + + $this->withDependencies(...$dependencies); + if (!$this->version && $version) { + $this->withVersion($version); + } + + return true; + } + + /** + * Searching for in directory of the Script: + * + * - {fileName}.asset.json + * - {fileName}.{hash}.asset.json + * - {fileName}.asset.php + * - {fileName}.{hash}.asset.php + * + * @return \DirectoryIterator|null + */ + protected function findDepdendencyFile(): ?\DirectoryIterator + { + try { + $filePath = $this->filePath(); + if ($filePath === '') { + return null; + } + + $path = dirname($filePath) . '/'; + + $fileName = str_replace([$path, '.js'], '', $filePath); + // It might be possible that the script file contains a version hash as well. + // So we need to split it apart and just use the first part of the file. + $fileNamePieces = explode('.', $fileName); + $fileName = $fileNamePieces[0]; + + $regex = '/' . $fileName . '(?:\.[a-zA-Z0-9]+)?\.asset\.(json|php)/'; + + $depsFile = null; + foreach (new \DirectoryIterator($path) as $fileInfo) { + if ( + $fileInfo->isDot() + || $fileInfo->isDir() + || !in_array($fileInfo->getExtension(), ['json', 'php'], true) + ) { + continue; + } + if (preg_match($regex, $fileInfo->getFilename())) { + $depsFile = $fileInfo; + break; + } + } + + return $depsFile; + } catch (\Throwable $exception) { + return null; + } + } +} diff --git a/vendor/inpsyde/assets/src/Style.php b/vendor/inpsyde/assets/src/Style.php new file mode 100644 index 000000000..82ee72723 --- /dev/null +++ b/vendor/inpsyde/assets/src/Style.php @@ -0,0 +1,158 @@ +> + */ + protected $cssVars = []; + + /** + * @return string + */ + public function media(): string + { + return $this->media; + } + + /** + * @param string $media + * + * @return static + */ + public function forMedia(string $media): Style + { + $this->media = $media; + + return $this; + } + + /** + * @return string[]|null + */ + public function inlineStyles(): ?array + { + return $this->inlineStyles; + } + + /** + * @param string $inline + * + * @return static + * + * @see https://codex.wordpress.org/Function_Reference/wp_add_inline_style + */ + public function withInlineStyles(string $inline): Style + { + if (!$this->inlineStyles) { + $this->inlineStyles = []; + } + + $this->inlineStyles[] = $inline; + + return $this; + } + + /** + * Add custom CSS properties (CSS vars) to an element. + * Those custom CSS vars will be enqueued with inline style + * to your handle. Variables will be automatically prefixed + * with '--'. + * + * @param string $element + * @param array $vars + * + * @return $this + * + * @example Style::withCssVars('.some-element', ['--white' => '#fff']); + * @example Style::withCssVars('.some-element', ['white' => '#fff']); + */ + public function withCssVars(string $element, array $vars): Style + { + if (!isset($this->cssVars[$element])) { + $this->cssVars[$element] = []; + } + + foreach ($vars as $key => $value) { + $key = substr($key, 0, 2) === '--' + ? $key + : '--' . $key; + + $this->cssVars[$element][$key] = $value; + } + + return $this; + } + + /** + * @return array> + */ + public function cssVars(): array + { + return $this->cssVars; + } + + /** + * @return string + */ + public function cssVarsAsString(): string + { + $return = ''; + foreach ($this->cssVars() as $element => $vars) { + $values = ''; + foreach ($vars as $key => $value) { + $values .= sprintf('%1$s:%2$s;', $key, $value); + } + $return .= sprintf('%1$s{%2$s}', $element, $values); + } + + return $return; + } + + /** + * Wrapper function to set AsyncStyleOutputFilter as filter. + * + * @return static + */ + public function useAsyncFilter(): Style + { + return $this->withFilters(AsyncStyleOutputFilter::class); + } + + /** + * {@inheritDoc} + */ + protected function defaultHandler(): string + { + return StyleHandler::class; + } +} diff --git a/vendor/inpsyde/assets/src/Util/AssetHookResolver.php b/vendor/inpsyde/assets/src/Util/AssetHookResolver.php new file mode 100644 index 000000000..506ede1cb --- /dev/null +++ b/vendor/inpsyde/assets/src/Util/AssetHookResolver.php @@ -0,0 +1,92 @@ +context = $context ?? WpContext::determine(); + } + + /** + * Resolving to the current location/page in WordPress all current hooks. + * + * @return string[] + */ + public function resolve(): array + { + $isLogin = $this->context->isLogin(); + $isFront = $this->context->isFrontoffice(); + $isActivate = $this->context->isWpActivate(); + + if (!$isActivate && !$isLogin && !$isFront && !$this->context->isBackoffice()) { + return []; + } + + if ($isLogin) { + return [Asset::HOOK_LOGIN]; + } + + if ($isActivate) { + return [Asset::HOOK_ACTIVATE]; + } + + // These hooks might be fired in both front and back office. + $assets = [Asset::HOOK_BLOCK_ASSETS]; + + if ($isFront) { + $assets[] = Asset::HOOK_FRONTEND; + $assets[] = Asset::HOOK_CUSTOMIZER_PREVIEW; + + return $assets; + } + + $assets[] = Asset::HOOK_BLOCK_EDITOR_ASSETS; + $assets[] = Asset::HOOK_CUSTOMIZER; + $assets[] = Asset::HOOK_BACKEND; + + return $assets; + } + + /** + * @return string|null + */ + public function lastHook(): ?string + { + switch (true) { + case $this->context->isLogin(): + return Asset::HOOK_LOGIN; + case $this->context->isFrontoffice(): + return Asset::HOOK_FRONTEND; + case $this->context->isBackoffice(): + return Asset::HOOK_BACKEND; + case $this->context->isWpActivate(): + return Asset::HOOK_ACTIVATE; + } + + return null; + } +} diff --git a/vendor/inpsyde/assets/src/Util/AssetPathResolver.php b/vendor/inpsyde/assets/src/Util/AssetPathResolver.php new file mode 100644 index 000000000..7b495511a --- /dev/null +++ b/vendor/inpsyde/assets/src/Util/AssetPathResolver.php @@ -0,0 +1,121 @@ + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/vendor/inpsyde/modularity/composer.json b/vendor/inpsyde/modularity/composer.json new file mode 100644 index 000000000..c1f808913 --- /dev/null +++ b/vendor/inpsyde/modularity/composer.json @@ -0,0 +1,73 @@ +{ + "name": "inpsyde/modularity", + "type": "library", + "description": "Modular PSR-11 implementation for WordPress plugins, themes or libraries.", + "license": "GPL-2.0-or-later", + "authors": [ + { + "name": "Inpsyde GmbH", + "email": "hello@inpsyde.com", + "homepage": "https://inpsyde.com/", + "role": "Company" + }, + { + "name": "Christian Leucht", + "email": "c.leucht@inpsyde.com", + "role": "Developer" + }, + { + "name": "Giuseppe Mazzapica", + "email": "g.mazzapica@inpsyde.com", + "role": "Developer" + } + ], + "require": { + "php": ">=7.2", + "ext-json": "*", + "psr/container": "^1.1.0 || ^2" + }, + "require-dev": { + "brain/monkey": "^2.6.1", + "inpsyde/php-coding-standards": "^1", + "mikey179/vfsstream": "^v1.6.10", + "phpunit/phpunit": "^8.5.21 || ^9.6.7", + "vimeo/psalm": "^4.13.1", + "php-stubs/wordpress-stubs": ">=5.8@stable", + "johnpbloch/wordpress-core": ">=5.8" + }, + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Inpsyde\\Modularity\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Inpsyde\\Modularity\\Tests\\": "tests/src/", + "Inpsyde\\Modularity\\Tests\\Unit\\": "tests/unit/" + } + }, + "minimum-stability": "dev", + "prefer-stable": true, + "scripts": { + "cs": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs", + "psalm": "@php ./vendor/vimeo/psalm/psalm", + "qa": [ + "@tests:no-cov", + "@cs", + "@psalm" + ], + "tests": "@php ./vendor/phpunit/phpunit/phpunit", + "tests:no-cov": "@php ./vendor/phpunit/phpunit/phpunit --no-coverage" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "composer/package-versions-deprecated": true + } + } +} diff --git a/vendor/inpsyde/modularity/docs/Application-flow.md b/vendor/inpsyde/modularity/docs/Application-flow.md new file mode 100644 index 000000000..7f259aa74 --- /dev/null +++ b/vendor/inpsyde/modularity/docs/Application-flow.md @@ -0,0 +1,100 @@ +# The application flow + +Modularity implements its application flow in two stages: + +- First, the application's dependencies tree is "composed" by collecting services declared in modules, adding sub-containers, and connecting other applications. +- After that, the application dependency tree is locked, and the services are "consumed" to execute their behavior. + +The `Package` class implements the two stages above, respectively, in the two methods: + +- **`Package::build()`** +- **`Package::boot()`** + +For convenience, `Package::boot()` is "smart enough" to call `build()` if it was not called before, so the following code (that makes the two stages evident): + +```php +Package::new($properties)->build()->boot(); +``` + +is entirely equivalent to the following: + +```php +Package::new($properties)->boot(); +``` + +Both stages are implemented through a series of *steps*, and the application status progresses as the steps are complete. In the process, a few action hooks are fired to allow external code to interact with the flow. + +At any point of the flow, by holding an instance of the `Package` is possible to inspect the current status via `Package::statusIs()`, passing as an argument one of the `Package::STATUS_*` constants. + + +## Building stage + +1. Upon instantiation, the `Package` status is at **`Package::STATUS_IDLE`** +2. Default modules can be added by calling **`Package::addModule()`** on the instance. +3. The **`Package::ACTION_INIT`** action hook is fired, passing the package instance as an argument. That allows external code to add modules. +4. The `Package` status moves to **`Package::STATUS_INITIALIZED`**. The "building" stage is completed, and no more modules can be added. + + +## Booting stage + +1. When the booting stage begins, the `Package` status moves to **`Package::STATUS_MODULES_ADDED`**. +2. A read-only PSR-11 container is created. It can lazily resolve the dependency tree defined in the previous stage. +3. **All executables modules run**. That is when all the application behavior happens. Note: Because the container is "lazy", only the consumed services are resolved. The `Package` never executes factory callbacks for services "registered" in the previous stage but not used in this stage. +4. The `Package` status moves to **`Package::STATUS_READY`**. +5. The **`Package::ACTION_READY`** action hook is fired, passing the package instance as an argument. External code hooking that action can access the read-only container instance, resolve services, and perform additional actions but not register modules. +6. The `Package` status moves to **`Package::STATUS_BOOTED`**. The booting stage is completed. `Package::boot()` returns true. + + +## The "failure flow" + +The steps listed above for the two stages represent the "happy paths". If any exception is thrown at any of the steps above, the flows are halted and the "failure flow" starts. + +### When the failure starts during the "building" stage + +1. The `Package` status moves to **`Package::STATUS_FAILED`**. +2. The **`Package::ACTION_FAILED_BUILD`** action hook is fired, passing the raised `Throwable` as an argument. +3. If the `Package`'s `Properties` instance is in "debug mode" (`Properties::isDebug()` returns `true`), the exception bubbles up, and the flow stops here. +4. If the `Properties` instance is _not_ in "debug mode", the **`Package::ACTION_FAILED_BOOT`** action hook is fired, passing a `Throwable` whose `previous` property is the `Throwable` thrown during the building stage. The "previous hierarchy" could be several levels if during the building stage many failures happened. +5. `Package::boot()` returns false. + +### When the failure starts during the "booting" stage + +1. The `Package` status moves to **`Package::STATUS_FAILED`**. +2. The **`Package::ACTION_FAILED_BOOT`** action hook is fired, passing the raised `Throwable` as an argument. +3. If the `Package`'s `Properties` instance is in "debug mode" (`Properties::isDebug()` returns `true`), the exception bubbles up, and the flow stops here. +4. `Package::boot()` returns false. + + +## A note about default modules passed to boot() + +The `Package::boot()` method accepts a list of modules. That has been deprecated since Modularity v1.7. + +Considering that `Package::boot()` represents the "booting" stage that is supposed to happen *after* the "building" stage, it might be hard to figure out where the addition of those modules fits in the flows described above. + +When `Package::boot()` is called without calling `Package::build()` first, as in: + +```php +Package::new($properties)->boot(new ModuleOne(), new ModuleTwo()); +``` + +The code is equivalent to the following: + +```php +Package::new($properties)->addModule(new ModuleOne())->addModule(new ModuleTwo())->boot(); +``` + +So the "building" flow is respected. + +However, when `Package::boot()` is called after `Package::build()`, as in: + +```php +Package::new($properties)->build()->boot(new ModuleOne(), new ModuleTwo()); +``` + +The `Package` is at the end of the "building" flow after `Package::build()` is called, but it must "jump" back in the middle of "building" flow to add the modules. + +In fact, after `Package::build()` is called the application status is at `Package::STATUS_INITIALIZED`, and no more modules can be added. + +However, for backward compatibility reasons, in that case, the `Package` temporarily "hacks" the status back to `Package::STATUS_IDLE` so modules can be added, and then resets it to `Package::STATUS_INITIALIZED` so that the "booting" stage can start as usual. + +This "hack" is why passing modules to `Package::boot()` has been deprecated and will be removed in the next major version when backward compatibility breaks are allowed. diff --git a/vendor/inpsyde/modularity/docs/Modules.md b/vendor/inpsyde/modularity/docs/Modules.md new file mode 100644 index 000000000..505b83795 --- /dev/null +++ b/vendor/inpsyde/modularity/docs/Modules.md @@ -0,0 +1,332 @@ +# Modules +Services can be _registered_, _extended_ and _booted_ via a so-called Module in your Application. + +Those Modules can be registered to your Application via the provided `ServiceModule`-, `FactoryModule`-, `ExtendingModule`- and `ExecutableModule`-interfaces. + +**Default Modules** are registered before `Package::boot()`: + +```php +addModule(new ModuleWhichProvidesServices()) + ->addModule(new ModuleWhichProvidesFactories()) + ->addModule(new ModuleWhichProviedsExtensions()) + ->addModule(new ModuleWhichIsExecuted()) + ->boot(); +``` + +Each Module implementation will extend the basic `Module`-interface which is required to define a `Module::id(): string`. This identifier will be re-used in Package-class to keep track of the current state of your Module and will allow easier debugging of your Application. To avoid defining this by hand, it is possible to use the following Trait: `Inpsyde\Modularity\Module\ModuleClassNameIdTrait` + +## ServiceModule +A ServiceModule will allow you to register new Services to the Container, to access them later on a specific point. The `ServiceModule::services(): array` will return an array of Services. Each array-key is an identifier for your Service, while the array-value will contain a callable which receives the primary Container (read-only) to set up your Service. + +Services registered via `ServiceModule::services()` will only be resolved and extended once and on continues access the same instance will be returned. + +```php + static function(ContainerInterface $container): ServiceOne { + return new ServiceOne(); + } + ]; + } +} +``` + +## FactoryModule +The `FactoryModule::factories(): array` will allow you to register new Services as factories. This means, that every time you’re accessing the Service via Container::get() you’ll get a new instance of the Service. + +```php + static function(ContainerInterface $container): FactoryServiceOne { + return new FactoryServiceOne(); + } + ]; + } +} +``` + +## ExtendingModule +The `ExtendingModule::extensions(): array` will allow you to return an array of Extensions for your Services. Those Extensions will be added to your Services after registration. Each Extension will return a callable function which will receive the original Service and the primary Container (read-only). + +```php + static function(ServiceOne $serviceOne, ContainerInterface $container): ExtendedServiceOne + { + return ExtendedServiceOne($serviceOne); + } + ]; + } +} +``` + +### Extending by type + +Sometimes it is desirable to extend a service by its type. Extending modules can do that as well: + +```php +use Inpsyde\Modularity\Module\ExtendingModule; +use Psr\Log\{LoggerInterface, LoggerAwareInterface}; + +class LoggerAwareExtensionModule implements ExtendingModule +{ + public function extensions() : array + { + return [ + '@instanceof' => static function( + LoggerAwareInterface $service, + ContainerInterface $c + ): ExtendedService { + + if ($c->has(LoggerInterface::class)) { + $service->setLogger($c->get(LoggerInterface::class)); + } + return $service; + } + ]; + } +} +``` + +#### Types and subtypes + +The `@instanceof` syntax works with class and interface names, targeting the given type and any +of its subtypes. + +For example, assuming the following objects: + +```php +interface Animal {} +class Dog implements Animal {} +class BullDog extends Dog {} +``` + +and the following module: + +```php +class AnimalsExtensionModule implements ExtendingModule +{ + public function extensions() : array + { + return [ + '@instanceof' => fn(Animal $animal) => $animal, + '@instanceof' => fn(Dog $dog) => $dog, + '@instanceof' => fn(BullDog $bullDog) => $bullDog, + ]; + } +} +``` + +A service of type `BullDog` would go through all the 3 extensions. + +Note how extending callbacks can always safely declare the parameter type using in the signature +the type they have in `@instanceof`. + +#### Precedence + +The precedence of extensions-by-type resolution goes as follows: + +1. Extensions added to exact class +2. Extensions added to any parent class +3. Extensions added to any implemented interface + +Inside each of the three "groups", extensions are processed in _FIFO_ mode: the first added are the +first processed. + +#### Name helper + +The syntax `"@instanceof"` is an hardcoded string that might be error prone to type. + +The method `use Inpsyde\Modularity\Container\ServiceExtensions::typeId()` might be used to avoid +using hardcode strings. For example: + +```php +use npsyde\Modularity\Container\ServiceExtensions; + +class AnimalsExtensionModule implements ExtendingModule +{ + public function extensions() : array + { + return [ + ServiceExtensions::typeId(Animal::class) => fn(Animal $animal) => $animal, + ServiceExtensions::typeId(Dog::class) => fn(Dog $dog) => $dog, + ServiceExtensions::typeId(BullDog::class) => fn(BullDog $bullDog) => $bullDog, + ]; + } +} +``` + +#### Only for objects + +Extensions-by-type only work for objects. Any usage of `@instanceof` syntax with a string that is +a class/interface name will be ignored. +That means it is not possible to extend by type scalar/array services nor pseudo-types like +`iterable` or `callable`. + +#### Possibly recursive + +Extensions by type might be recursive. For example, an extension for type `A` that returns an +instance of `B` will prevent further extensions to type `A` to execute (unless `B` is a child of `A`) +and will trigger execution of extensions for type `B`. +**Infinite recursion is prevented**. So if extensions for `A` return `B` and extensions for `B` +return `A` that's where it stops, returning an `A` instance. + +#### Use carefully + +**Please note**: extensions-by-type have a performance impact especially when type extensions are +used to return a different type, because of possible recursions. +As a reference, it was measured that resolving 10000 objects in the container, each having 9 +extensions-by-type callbacks, on a very fast server, on PHP 8, for one concurrent user, takes +between 80 and 90 milliseconds. + +## ExecutableModule +If there is functionality that needs to be executed, you can make the Module executable like following: + +```php +get(ServiceOne::class); + add_action('init', $serviceOne); + + return true; + } +} +``` + +The return value true/false will determine if the Module has successfully been executed or not. + +### Context-based execution of Services +To execute Services based on a Context like “Rest Request” or “FrontOffice” we recommend the usage of [inpsyde/wp-context](https://github.com/inpsyde/wp-context). This package allows you to access the current request context and based on that you can execute your Services: + +```php +is(WpContext::AJAX, WpContext::CRON)) { + return false; + } + + // stuff for requests that are either AJAX or WP cron + $serviceOne = $container->get(ServiceOne::class); + add_action('init', $serviceOne); + + return true; + } +} +``` + +### Service/Factory overrides +When the same Service id is registered more than once by multiple modules, the latter will override the former. + +```php + static function(ContainerInterface $container): ServiceOne { + return new ServiceOne(); + } + ]; + } +} + +class ModuleWhichOverridesServices implements ServiceModule +{ + use ModuleClassNameIdTrait; + + public function services() : array + { + return [ + ServiceOne::class => static function(ContainerInterface $container): ServiceOne { + return new class extends ServiceOne{ + /* */ + }; + } + ]; + } +} +``` + +*For module developers* this opens up some possibilities, like the ability to inject Mocks in the container, or work around +scenarios where the use of extensions would result in an unneeded and/or wasteful constructor call of the now-obsolete +original. + +*For package maintainers* this is something to watch out for when consuming Modules from multiple sources. +However unlikely it may be, there is a risk of _unintentional_ overrides resulting in unexpected behaviour. diff --git a/vendor/inpsyde/modularity/docs/PSR-11-Container.md b/vendor/inpsyde/modularity/docs/PSR-11-Container.md new file mode 100644 index 000000000..542b0dbbd --- /dev/null +++ b/vendor/inpsyde/modularity/docs/PSR-11-Container.md @@ -0,0 +1,15 @@ +# Default Container based on PSR-11 +The used Container in your Application is based on PSR-11 and allows you via Modules to set, extend and get Services. The consuming Services from your Modules has read-only access to the Container. Adding new Factories to the Container will only be possible via an own Container or a Module. + +The default (primary) Container is a delegating Container and receives aside from Factories, Extensions also PSR-based child Containers, which are registered via Package-class. If a Service cannot be resolved via the primary Container, it will resort to the has and get methods of the delegates to resolve the requested Service. Additionally, the primary Container will allow you not only to access Services, it will also allow you to extend Services from child Containers. + +You can simply register an own PSR-Container via Package like following: + +```php +boot(); +``` diff --git a/vendor/inpsyde/modularity/docs/Package.md b/vendor/inpsyde/modularity/docs/Package.md new file mode 100644 index 000000000..b25fdef42 --- /dev/null +++ b/vendor/inpsyde/modularity/docs/Package.md @@ -0,0 +1,274 @@ +# Package +This is the central class, which will allow you to add multiple Containers, register Modules and use Properties to get more information about your Application. + +Aside from that, the `Package`-class will boot your Application on a specific point (like plugins_loaded) and grants access for other Applications via hook to register and extend Services via Modules. + +```php +boot(); +``` + +The `Package`-class contains the following public API: + +**Package::moduleStatus(): array** + +Returns an array of all Modules and the current status. + +**Package::moduleIs(string $moduleId, string $status): bool** + +Allows to check the status for a given `Module::id()`. + +Following `Module` statuses are available: + +| Status | Description | +| -------------------------------------- | ------------------------------------------------------------ | +| `Package::MODULE_REGISTERED` | A `ServiceModule` was added and returned a non-zero number of services. | +| `Package::MODULE_REGISTERED_FACTORIES` | A `FactoryModule` was added and returned a non-zero number of factories. | +| `Package::MODULE_EXTENDED` | An `ExtendingModule` was added and returned a non-zero number of extension. | +| `Package::MODULE_ADDED` | _Any_ of the three statuses above applied, or a module implements `ExecutableModule` | +| `Package::MODULE_NOT_ADDED` | _None_ of the first three statuses applied for a modules that is non-executable. That might happen in two scenarios: a module only implemented base `Module` interface, or did not return any service/factory/extension. | +| `Package::MODULE_EXECUTED` | An `ExecutableModule::run()` method was called and returned `true`. | +| `Package::MODULE_EXECUTION_FAILED` | An `ExecutableModule::run()` method was called and returned `false`. | + +**Package::hookName(string $suffix = ''): string** + +Allows to generate the hookName for Package-class (see below) + +**Package::properties(): PropertiesInterface** + +Access to Properties. + +**Package::container(): ContainerInterface** + +Access to the compiled Container after the booting process is finished. + +**Package::name():string** + +A shortcut to `Properties::baseName()` which contains the name of your Application + +**Package::addModule(Module $module): self** + +Allows adding Modules from outside via custom Hooks triggered. + +**Package::statusIs(int $status): bool** + +Retrieve the current status of the Application. Following are available: + +- `Package::STATUS_IDLE` - before Application is booted. +- `Package::STATUS_INITIALIZED` - after first init action is triggered. +- `Package::STATUS_MODULES_ADDED` - after all modules have been added. +- `Package::STATUS_READY` - after the "ready" action has been fired. +- `Package::STATUS_BOOTED` - Application has successfully booted. +- `Package::STATUS_FAILED_BOOT` - when Application did not boot properly. + + + +## Access from external + +The recommended way to set up your Application is to provide a function in your Application namespace which returns an instance of Package. Here’s a short example of an “Acme”-Plugin: + +```php +boot(); + } +); +``` + +By providing the `Acme\plugin()` function, you’ll enable external code to hook into your application: + +```php +hookName(Package::ACTION_INIT), + static function (Package $plugin): void { + $plugin->addModule(new MyModule()); + } +); +``` + +## Building the package + +Sometimes, especially in unit tests, it might be desirable to obtain services as defined for the +production code, but without calling any `ExecutableModule::run()`, which usually contains +WP-dependant code, and therefore requires heavy mocking. + +For example, assuming a common `plugin()` function like the following: + +```php +function plugin(): Modularity\Package { + static $package; + if (!$package) { + $properties = Modularity\Properties\PluginProperties::new(__FILE__); + $package = Modularity\Package::new($properties) + ->addModule(new ModuleOne()) + ->addModule(new ModuleTwo()) + } + return $package; +} +``` + +In unit test it will be possible (as of v1.7+) to do something like the following: + +```php +$myService = plugin()->build()->container()->get(MyService::class); +static::assertTrue($myService->isValid()); +``` + +### Booting a built container + +The `Package::boot()` method can be called on already built package. + +For example, the following is a valid unit test code: + +```php +$plugin = plugin()->build(); +$myService = $plugin->container()->get(MyService::class); + +static::assertTrue($myService->isValid()); +static::assertFalse($myService->isBooted()); + +$plugin->boot(); + +static::assertTrue($myService->isBooted()); +``` + +### Deprecated boot parameters + +Before Modularity v1.7.0, it was an accepted practice to pass default modules to `Package::boot()`, +as in: + +```php +add_action( + 'plugins_loaded', + static function(): void { + plugin()->boot(new ModuleOne(), new ModuleTwo()); + } +); +``` + +This is now deprecated to allow a better separation of the "building" and "booting" steps. + +While it still works (and it will work up to version 2.0), it will emit a deprecation notice. + +The replacement is using `Package::addModule()`: + +```php +plugin()->addModule(new ModuleOne())->addModule(new ModuleTwo())->boot(); +``` + +There's only one case in which calling `Package::boot()` with default modules will throw an +exception (besides triggering a deprecated notice), that is when a passed modules was not added +before `Package::addModule()` and an instance of the container was already obtained from the package. + +For example, this will throw an exception: + +```php +$plugin = plugin()->build(); + +// Now that container is built, passing modules to `boot()` will raise an exception, because we +// can't add new modules to an already "compiled" container being that read-only. +$container = $plugin->container(); + +$plugin->boot(new ModuleOne()); +``` + +To prevent the exception it would be necessary to add the module before calling `build()`, or alternatively, to call `$plugin->boot(new ModuleOne())` _before_ calling `$plugin->container()`. +In this latter case the exception is not thrown, but the deprecation will still be emitted. + + +## Connecting packages + +Every `Package` has a separate container, however sometimes it might be desirable access another package's services. For example from a plugin access one library services, or from a theme access a plugin's services. + +That can be done using the `Package::connect()` method. + +For example: + +```php +// a theme functions.php + +$properties = Properties\ThemeProperties::new('/path/to/theme/dir/'); +$theme = Inpsyde\Modularity\Package::new($properties); + +$theme->connect(\Acme\plugin()); +$theme->boot(); +``` + +To note: + +- `Package::connect()` must be called **before** boot. If called later, no connections happen and it returns `false` +- The package to be connected might be already booted or not. In the second case the connection will happen, but before accessing its services it has to be booted, or an exception will happen. + +Package connection is a great way to create reusable libraries and services that can be used by many plugins. For example, it might be possible to have a *library* that has something like this: + +```php +namespace Acme; + +function myLibrary(): Package { + static $lib; + if (!$lib) { + $properties = Properties\LibraryProperties::new('path/to/composer.json'); + $lib = Inpsyde\Modularity\Package::new($properties); + $lib->addModule(new ModuleOne()); + $lib->addModule(new ModuleTwo()); + $lib->boot(); + } + return $lib; +} +``` + +This would be autoloaded by Composer, but not being a plugin will not be called by WordPress. + +However, *many* plugins in the same installation could do: + +```php +/** @var Package $plugin */ +$plugin->connect(\Acme\myLibrary()); +``` + +Thanks to that, all plugins will be able to access the library's services in the same way they access own modules' services. + + + +### Accessing connected packages' properties + +In modules, we can access package properties calling `$container->get(Package::PROPERTIES)`. If we'd like to access any connected package properties, we could do that using a key whose format is: `sprintf('%s.%s', $connectedPackage->name(), Package::PROPERTIES)`. diff --git a/vendor/inpsyde/modularity/docs/Properties.md b/vendor/inpsyde/modularity/docs/Properties.md new file mode 100644 index 000000000..aca1ad5e5 --- /dev/null +++ b/vendor/inpsyde/modularity/docs/Properties.md @@ -0,0 +1,140 @@ +# Properties +Properties containing additional information about your Application and can be built based on Themes, Plugins or Libraries. The Properties itself are immutable and only grant access to values after they were injected into the Package-class. + +Properties are added to the Package-class and automatically added as a Service to the primary Container. + +To access Properties in your application via Container you can use the class constant `Package::PROPERTIES`: + +```php +get(Package::PROPERTIES); + + return true; + } +} +``` + +A specific instance of your Properties will use the following data: + +| Properties method | Theme - style.css | Plugin - file header | Library - composer.json | +| --- | --- | --- | --- | +| Properties::author() | Author | Author | authors[0].name | +| Properties::authorUri() | Author URI | Author URI | authors[0].homepage | +| Properties::description() | Description | Description | description | +| Properties::domainPath() | Domain Path | Domain Path | extra.modularity.domainPath | +| Properties::name() | Theme Name | Plugin Name | extra.modularity.name | +| Properties::textDomain() | Text Domain | Text Domain | extra.modularity.textDomain | +| Properties::uri() | Theme URI | Plugin URI | extra.modularity.uri | +| Properties::version() | Version | Version | version
extra.modularity.version | +| Properties::requiresWp() | Requires at least | Requires at least | extra.modularity.requiresWp | +| Properties::requiresPhp() | Requires PHP | Requires PHP | require.php
require-dev.php | +| Properties::baseUrl() | WP_Theme::get_stylesheet_directory_uri() | plugins_url() | | +| Properties::network() | | Network | | +| Properties::status() | Status | | | +| Properties::tags() | Tags | | keywords | +| Properties::template() | Template | | | + + + +### Accessing connected packages' properties + +When we have packages connected via `Package::connect()`, to access connected packages' properties, we could do that using a container key whose format is: `sprintf('%s.%s', $connectedPackage->name(), Package::PROPERTIES)`. + + + +## PluginProperties + +Inside your Plugin you can use the following code to automatically generate Properties based on the [Plugins Header](https://developer.wordpress.org/reference/functions/get_plugin_data/): + +```php +withBaseUrl($url); +``` + +Please note that `withBaseUrl()` will only work if a base URL is not set already, otherwise it will +throw an exception. + +Additionally, `LibraryProperties` will have the following public API: + +- `LibraryProperties::tags(): array` - returns a list of keywords defined in composer.json. diff --git a/vendor/inpsyde/modularity/docs/_config.yml b/vendor/inpsyde/modularity/docs/_config.yml new file mode 100644 index 000000000..4da9e397f --- /dev/null +++ b/vendor/inpsyde/modularity/docs/_config.yml @@ -0,0 +1,40 @@ +title: Inpsyde Modularity +description: >- + inpsyde/modularity is a modular PSR-11 implementation for WordPress Plugins, Themes or Libraries. + +baseurl: /modularity # Your repo name with a leading slash. + +# Aux links for the upper right navigation +aux_links: + "Inpsyde Modularity on GitHub": + - https://github.com/inpsyde/modularity + +# Footer "Edit this page on GitHub" link text +gh_edit_repository: https://github.com/inpsyde/modularity # Your repo GitHub URL + +# Everything above is repo specific. + +############################################################### + +# This section is repo specific. These can be omitted if defaults make sense. + +gh_edit_branch: master # The default branch of the repo. Default: main +gh_edit_source: docs # The directory containing the docs. Default: docs + +############################################################### + +# Everything below should be copy and pasted into package repos +remote_theme: inpsyde/jekyll-syde-theme + +############################################################### + +# Everything below should be copy and pasted into package repos +# To be replaced by jekyll-inpsyde-theme's `_config.yml` when GitHub Pages supports Jekyll v4. + +plugins: + - jekyll-remote-theme + - jekyll-seo-tag + - jekyll-sitemap + - jemoji + +permalink: pretty diff --git a/vendor/inpsyde/modularity/src/Container/ContainerConfigurator.php b/vendor/inpsyde/modularity/src/Container/ContainerConfigurator.php new file mode 100644 index 000000000..64a8d2b5c --- /dev/null +++ b/vendor/inpsyde/modularity/src/Container/ContainerConfigurator.php @@ -0,0 +1,153 @@ + + */ + private $services = []; + + /** + * @var array + */ + private $factoryIds = []; + + /** + * @var ServiceExtensions + */ + private $extensions; + + /** + * @var ContainerInterface[] + */ + private $containers = []; + + /** + * @var null|ContainerInterface + */ + private $compiledContainer; + + /** + * ContainerConfigurator constructor. + * + * @param ContainerInterface[] $containers + */ + public function __construct(array $containers = [], ?ServiceExtensions $extensions = null) + { + array_map([$this, 'addContainer'], $containers); + $this->extensions = $extensions ?? new ServiceExtensions(); + } + + /** + * Allowing to add child containers. + * + * @param ContainerInterface $container + */ + public function addContainer(ContainerInterface $container): void + { + $this->containers[] = $container; + } + + /** + * @param string $id + * @param Service $factory + */ + public function addFactory(string $id, callable $factory): void + { + $this->addService($id, $factory); + // We're using a hash table to detect later + // via isset() if a Service as a Factory. + $this->factoryIds[$id] = true; + } + + /** + * @param string $id + * @param Service $service + * + * @return void + */ + public function addService(string $id, callable $service): void + { + /* + * We are being intentionally permissive here, + * allowing a simple workflow for *intentional* overrides + * while accepting the (small?) risk of *accidental* overrides + * that could be hard to notice and debug. + * + * Clear a factory flag in case it was a factory. + * If needs be, it will get re-added after this function completes. + */ + unset($this->factoryIds[$id]); + + $this->services[$id] = $service; + } + + /** + * @param string $id + * + * @return bool + */ + public function hasService(string $id): bool + { + if (array_key_exists($id, $this->services)) { + return true; + } + + foreach ($this->containers as $container) { + if ($container->has($id)) { + return true; + } + } + + return false; + } + + /** + * @param string $id + * @param ExtendingService $extender + * + * @return void + */ + public function addExtension(string $id, callable $extender): void + { + $this->extensions->add($id, $extender); + } + + /** + * @param string $id + * + * @return bool + */ + public function hasExtension(string $id): bool + { + return $this->extensions->has($id); + } + + /** + * Returns a read only version of this Container. + * + * @return ContainerInterface + */ + public function createReadOnlyContainer(): ContainerInterface + { + if (!$this->compiledContainer) { + $this->compiledContainer = new ReadOnlyContainer( + $this->services, + $this->factoryIds, + $this->extensions, + $this->containers + ); + } + + return $this->compiledContainer; + } +} diff --git a/vendor/inpsyde/modularity/src/Container/PackageProxyContainer.php b/vendor/inpsyde/modularity/src/Container/PackageProxyContainer.php new file mode 100644 index 000000000..d5e3954f9 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Container/PackageProxyContainer.php @@ -0,0 +1,102 @@ +package = $package; + } + + /** + * @param string $id + * @return mixed + * + * @throws \Exception + */ + public function get(string $id) + { + $this->assertPackageBooted($id); + + return $this->container->get($id); + } + + /** + * @param string $id + * @return bool + * + * @throws \Exception + */ + public function has(string $id): bool + { + return $this->tryContainer() && $this->container->has($id); + } + + /** + * @return bool + * + * @throws \Exception + * @psalm-assert-if-true ContainerInterface $this->container + */ + private function tryContainer(): bool + { + if ($this->container) { + return true; + } + + /** TODO: We need a better way to deal with status checking besides equality */ + if ( + $this->package->statusIs(Package::STATUS_READY) + || $this->package->statusIs(Package::STATUS_BOOTED) + ) { + $this->container = $this->package->container(); + } + + return (bool)$this->container; + } + + /** + * @param string $id + * @return void + * + * @throws \Exception + * + * @psalm-assert ContainerInterface $this->container + */ + private function assertPackageBooted(string $id): void + { + if ($this->tryContainer()) { + return; + } + + $name = $this->package->name(); + $status = $this->package->statusIs(Package::STATUS_FAILED) + ? 'is errored' + : 'is not ready yet'; + + throw new class ("Error retrieving service {$id} because package {$name} {$status}.") + extends \Exception + implements ContainerExceptionInterface { + }; + } +} diff --git a/vendor/inpsyde/modularity/src/Container/ReadOnlyContainer.php b/vendor/inpsyde/modularity/src/Container/ReadOnlyContainer.php new file mode 100644 index 000000000..4dd862db7 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Container/ReadOnlyContainer.php @@ -0,0 +1,163 @@ + + */ + private $services; + + /** + * @var array + */ + private $factoryIds; + + /** + * @var ServiceExtensions + */ + private $extensions; + + /** + * Resolved factories. + * + * @var array + */ + private $resolvedServices = []; + + /** + * @var ContainerInterface[] + */ + private $containers; + + /** + * ReadOnlyContainer constructor. + * + * @param array $services + * @param array $factoryIds + * @param ServiceExtensions|array $extensions + * @param ContainerInterface[] $containers + */ + public function __construct( + array $services, + array $factoryIds, + $extensions, + array $containers + ) { + $this->services = $services; + $this->factoryIds = $factoryIds; + $this->extensions = $this->configureServiceExtensions($extensions); + $this->containers = $containers; + } + + /** + * @param string $id + * + * @return mixed + */ + public function get(string $id) + { + if (array_key_exists($id, $this->resolvedServices)) { + return $this->resolvedServices[$id]; + } + + if (array_key_exists($id, $this->services)) { + $service = $this->services[$id]($this); + $resolved = $this->extensions->resolve($service, $id, $this); + + if (!isset($this->factoryIds[$id])) { + $this->resolvedServices[$id] = $resolved; + unset($this->services[$id]); + } + + return $resolved; + } + + foreach ($this->containers as $container) { + if ($container->has($id)) { + $service = $container->get($id); + + return $this->extensions->resolve($service, $id, $this); + } + } + + throw new class ("Service with ID {$id} not found.") + extends \Exception + implements NotFoundExceptionInterface { + }; + } + + /** + * @param string $id + * + * @return bool + */ + public function has(string $id): bool + { + if (array_key_exists($id, $this->services)) { + return true; + } + + if (array_key_exists($id, $this->resolvedServices)) { + return true; + } + + foreach ($this->containers as $container) { + if ($container->has($id)) { + return true; + } + } + + return false; + } + + /** + * Support extensions as array or ServiceExtensions instance for backward compatibility. + * + * With PHP 8+ we could use an actual union type, but when we bump to PHP 8 as min supported + * version, we will probably bump major version as well, so we can just get rid of support + * for array. + * + * @param mixed $extensions + * @return ServiceExtensions + */ + private function configureServiceExtensions($extensions): ServiceExtensions + { + if ($extensions instanceof ServiceExtensions) { + return $extensions; + } + + if (!is_array($extensions)) { + throw new \TypeError( + sprintf( + '%s::%s(): Argument #3 ($extensions) must be of type %s|array, %s given', + __CLASS__, + '__construct', + ServiceExtensions::class, + gettype($extensions) + ) + ); + } + + $servicesExtensions = new ServiceExtensions(); + foreach ($extensions as $id => $callback) { + /** + * @var string $id + * @var ExtendingService $callback + */ + $servicesExtensions->add($id, $callback); + } + + return $servicesExtensions; + } +} diff --git a/vendor/inpsyde/modularity/src/Container/ServiceExtensions.php b/vendor/inpsyde/modularity/src/Container/ServiceExtensions.php new file mode 100644 index 000000000..63fb1f6e6 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Container/ServiceExtensions.php @@ -0,0 +1,175 @@ +> + */ + protected $extensions = []; + + /** + * @param string $type + * @return string + */ + final public static function typeId(string $type): string + { + return "@instanceof<{$type}>"; + } + + /** + * @param string $extensionId + * @param ExtendingService $extender + * @return static + */ + public function add(string $extensionId, callable $extender): ServiceExtensions + { + isset($this->extensions[$extensionId]) or $this->extensions[$extensionId] = []; + $this->extensions[$extensionId][] = $extender; + + return $this; + } + + /** + * @param string $extensionId + * @return bool + */ + public function has(string $extensionId): bool + { + return isset($this->extensions[$extensionId]); + } + + /** + * @param mixed $service + * @param string $id + * @param Container $container + * @return mixed + */ + final public function resolve($service, string $id, Container $container) + { + $service = $this->resolveById($id, $service, $container); + + return is_object($service) + ? $this->resolveByType(get_class($service), $service, $container) + : $service; + } + + /** + * @param string $id + * @param mixed $service + * @param Container $container + * @return mixed + */ + protected function resolveById(string $id, $service, Container $container) + { + foreach ($this->extensions[$id] ?? [] as $extender) { + $service = $extender($service, $container); + } + + return $service; + } + + /** + * @param string $className + * @param object $service + * @param Container $container + * @param array $extendedClasses + * @return mixed + */ + protected function resolveByType( + string $className, + object $service, + Container $container, + array $extendedClasses = [] + ) { + + $extendedClasses[] = $className; + + /** @var array> $allCallbacks */ + $allCallbacks = []; + + // 1st group of extensions: targeting exact class + $byClass = $this->extensions[self::typeId($className)] ?? null; + $byClass and $allCallbacks[$className] = $byClass; + + // 2nd group of extensions: targeting parent classes + /** @var class-string $parentName */ + foreach (class_parents($service, false) ?: [] as $parentName) { + $byParent = $this->extensions[self::typeId($parentName)] ?? null; + $byParent and $allCallbacks[$parentName] = $byParent; + } + + // 3rd group of extensions: targeting implemented interfaces + /** @var class-string $interfaceName */ + foreach (class_implements($service, false) ?: [] as $interfaceName) { + $byInterface = $this->extensions[self::typeId($interfaceName)] ?? null; + $byInterface and $allCallbacks[$interfaceName] = $byInterface; + } + + $resultType = self::SERVICE_TYPE_NOT_CHANGED; + /** @var class-string $type */ + foreach ($allCallbacks as $type => $extenders) { + // When the previous group of callbacks resulted in a type change, we need to check + // type before processing next group. + if (($resultType === self::SERVICE_TYPE_CHANGED) && !is_a($service, $type)) { + continue; + } + [$service, $resultType] = $this->extendByType($type, $service, $container, $extenders); + if ($resultType === self::SERVICE_TYPE_NOT_OBJECT) { + // Service is not an object anymore, let's return it. + return $service; + } + } + + // If type changed since beginning, let's start over. + // We check if class was already extended to avoid infinite recursion. E.g. instead of: + // `-> extend(A): B -> extend(B): A -> *loop* ->` + // we have: + // `-> extend(A): B -> extend(B): A -> return A`. + $newClassName = get_class($service); + if (!in_array($newClassName, $extendedClasses, true)) { + return $this->resolveByType($newClassName, $service, $container, $extendedClasses); + } + + return $service; + } + + /** + * @param class-string $type + * @param object $service + * @param Container $container + * @param list $extenders + * @return array{mixed, int} + */ + private function extendByType( + string $type, + object $service, + Container $container, + array $extenders + ): array { + + foreach ($extenders as $extender) { + $service = $extender($service, $container); + if (!is_object($service)) { + return [$service, self::SERVICE_TYPE_NOT_OBJECT]; + } + if (!is_a($service, $type)) { + return [$service, self::SERVICE_TYPE_CHANGED]; + } + } + + return [$service, self::SERVICE_TYPE_NOT_CHANGED]; + } +} diff --git a/vendor/inpsyde/modularity/src/Module/ExecutableModule.php b/vendor/inpsyde/modularity/src/Module/ExecutableModule.php new file mode 100644 index 000000000..cd03b8f67 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Module/ExecutableModule.php @@ -0,0 +1,21 @@ + + */ + public function extensions(): array; +} diff --git a/vendor/inpsyde/modularity/src/Module/FactoryModule.php b/vendor/inpsyde/modularity/src/Module/FactoryModule.php new file mode 100644 index 000000000..10517f2f1 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Module/FactoryModule.php @@ -0,0 +1,21 @@ + + */ + public function factories(): array; +} diff --git a/vendor/inpsyde/modularity/src/Module/Module.php b/vendor/inpsyde/modularity/src/Module/Module.php new file mode 100644 index 000000000..353236b11 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Module/Module.php @@ -0,0 +1,20 @@ + + */ + public function services(): array; +} diff --git a/vendor/inpsyde/modularity/src/Package.php b/vendor/inpsyde/modularity/src/Package.php new file mode 100644 index 000000000..f75ccd91b --- /dev/null +++ b/vendor/inpsyde/modularity/src/Package.php @@ -0,0 +1,731 @@ + + * $package = Package::new(); + * $package->boot(); + * + * $container = $package->container(); + * $container->has(Package::PROPERTIES); + * $container->get(Package::PROPERTIES); + * + * + * @var string + */ + public const PROPERTIES = 'properties'; + + /** + * Custom action to be used to add Modules to the package. + * It might also be used to access package properties. + * + * @example + * + * $package = Package::new(); + * + * add_action( + * $package->hookName(Package::ACTION_INIT), + * $callback + * ); + * + */ + public const ACTION_INIT = 'init'; + + /** + * Custom action which is triggered after the application + * is booted to access container and properties. + * + * @example + * + * $package = Package::new(); + * + * add_action( + * $package->hookName(Package::ACTION_READY), + * $callback + * ); + * + */ + public const ACTION_READY = 'ready'; + + /** + * Custom action which is triggered when a failure happens during the building stage. + * + * @example + * + * $package = Package::new(); + * + * add_action( + * $package->hookName(Package::ACTION_FAILED_BUILD), + * $callback + * ); + * + */ + public const ACTION_FAILED_BUILD = 'failed-build'; + + /** + * Custom action which is triggered when a failure happens during the booting stage. + * + * @example + * + * $package = Package::new(); + * + * add_action( + * $package->hookName(Package::ACTION_FAILED_BOOT), + * $callback + * ); + * + */ + public const ACTION_FAILED_BOOT = 'failed-boot'; + + /** + * Custom action which is triggered when a package is connected. + */ + public const ACTION_PACKAGE_CONNECTED = 'package-connected'; + + /** + * Custom action which is triggered when a package cannot be connected. + */ + public const ACTION_FAILED_CONNECTION = 'failed-connection'; + + /** + * Module states can be used to get information about your module. + * + * @example + * + * $package = Package::new(); + * $package->moduleIs(SomeModule::class, Package::MODULE_ADDED); // false + * $package->addModule(new SomeModule()); + * $package->moduleIs(SomeModule::class, Package::MODULE_ADDED); // true + * + */ + public const MODULE_ADDED = 'added'; + public const MODULE_NOT_ADDED = 'not-added'; + public const MODULE_REGISTERED = 'registered'; + public const MODULE_REGISTERED_FACTORIES = 'registered-factories'; + public const MODULE_EXTENDED = 'extended'; + public const MODULE_EXECUTED = 'executed'; + public const MODULE_EXECUTION_FAILED = 'executed-failed'; + public const MODULES_ALL = '*'; + + /** + * Custom states for the class. + * + * @example + * + * $package = Package::new(); + * $package->statusIs(Package::IDLE); // true + * $package->boot(); + * $package->statusIs(Package::BOOTED); // true + * + */ + public const STATUS_IDLE = 2; + public const STATUS_INITIALIZED = 4; + public const STATUS_MODULES_ADDED = 5; + public const STATUS_READY = 7; + public const STATUS_BOOTED = 8; + public const STATUS_FAILED = -8; + + /** + * Current state of the application. + * + * @see Package::STATUS_* + * + * @var int + */ + private $status = self::STATUS_IDLE; + + /** + * Contains the progress of all modules. + * + * @see Package::moduleProgress() + * + * @var array> + */ + private $moduleStatus = [self::MODULES_ALL => []]; + + /** + * Hashmap of where keys are names of connected packages, and values are boolean, true + * if connection was successful. + * + * @see Package::connect() + * + * @var array + */ + private $connectedPackages = []; + + /** + * @var list + */ + private $executables = []; + + /** + * @var Properties + */ + private $properties; + + /** + * @var ContainerConfigurator + */ + private $containerConfigurator; + + /** + * @var bool + */ + private $built = false; + + /** + * @var bool + */ + private $hasContainer = false; + + /** + * @var \Throwable|null + */ + private $lastError = null; + + /** + * @param Properties $properties + * @param ContainerInterface[] $containers + * + * @return Package + */ + public static function new(Properties $properties, ContainerInterface ...$containers): Package + { + return new self($properties, ...$containers); + } + + /** + * @param Properties $properties + * @param ContainerInterface[] $containers + */ + private function __construct(Properties $properties, ContainerInterface ...$containers) + { + $this->properties = $properties; + + $this->containerConfigurator = new ContainerConfigurator($containers); + $this->containerConfigurator->addService( + self::PROPERTIES, + static function () use ($properties) { + return $properties; + } + ); + } + + /** + * @param Module $module + * + * @return static + * @throws \Exception + */ + public function addModule(Module $module): Package + { + try { + $this->assertStatus(self::STATUS_IDLE, sprintf('add module %s', $module->id())); + + $registeredServices = $this->addModuleServices( + $module, + self::MODULE_REGISTERED + ); + $registeredFactories = $this->addModuleServices( + $module, + self::MODULE_REGISTERED_FACTORIES + ); + $extended = $this->addModuleServices( + $module, + self::MODULE_EXTENDED + ); + $isExecutable = $module instanceof ExecutableModule; + + // ExecutableModules are collected and executed on Package::boot() + // when the Container is being compiled. + if ($isExecutable) { + /** @var ExecutableModule $module */ + $this->executables[] = $module; + } + + $added = $registeredServices || $registeredFactories || $extended || $isExecutable; + $status = $added ? self::MODULE_ADDED : self::MODULE_NOT_ADDED; + $this->moduleProgress($module->id(), $status); + } catch (\Throwable $throwable) { + $this->handleFailure($throwable, self::ACTION_FAILED_BUILD); + } + + return $this; + } + + /** + * @param Package $package + * @return bool + * @throws \Exception + */ + public function connect(Package $package): bool + { + try { + if ($package === $this) { + return false; + } + + $packageName = $package->name(); + $errorData = ['package' => $packageName, 'status' => $this->status]; + $errorMessage = "Failed connecting package {$packageName}"; + + // Don't connect, if already connected + if (array_key_exists($packageName, $this->connectedPackages)) { + $error = "{$errorMessage} because it was already connected."; + do_action( + $this->hookName(self::ACTION_FAILED_CONNECTION), + $packageName, + new \WP_Error('already_connected', $error, $errorData) + ); + + throw new \Exception($error, 0, $this->lastError); + } + + // Don't connect, if already booted or boot failed + $failed = $this->statusIs(self::STATUS_FAILED); + if ($failed || $this->statusIs(self::STATUS_BOOTED)) { + $status = $failed ? 'errored' : 'booted'; + $error = "{$errorMessage} to a {$status} package."; + do_action( + $this->hookName(self::ACTION_FAILED_CONNECTION), + $packageName, + new \WP_Error("no_connect_on_{$status}", $error, $errorData) + ); + + throw new \Exception($error, 0, $this->lastError); + } + + $this->connectedPackages[$packageName] = true; + + // We put connected package's properties in this package's container, so that in modules + // "run" method we can access them if we need to. + $this->containerConfigurator->addService( + sprintf('%s.%s', $package->name(), self::PROPERTIES), + static function () use ($package): Properties { + return $package->properties(); + } + ); + + // If the other package is booted, we can obtain a container, otherwise + // we build a proxy container + $container = $package->statusIs(self::STATUS_BOOTED) + ? $package->container() + : new PackageProxyContainer($package); + + $this->containerConfigurator->addContainer($container); + + do_action( + $this->hookName(self::ACTION_PACKAGE_CONNECTED), + $packageName, + $this->status, + $container instanceof PackageProxyContainer + ); + + return true; + } catch (\Throwable $throwable) { + if (isset($packageName)) { + $this->connectedPackages[$packageName] = false; + } + $this->handleFailure($throwable, self::ACTION_FAILED_BUILD); + + return false; + } + } + + /** + * @return static + */ + public function build(): Package + { + try { + // Don't allow building the application multiple times. + $this->assertStatus(self::STATUS_IDLE, 'build package'); + + do_action( + $this->hookName(self::ACTION_INIT), + $this + ); + // Changing the status here ensures we can not call this method again, and also we can not + // add new modules, because both this and `addModule()` methods check for idle status. + // For backward compatibility, adding new modules via `boot()` will still be possible, even + // if deprecated, at the condition that the container was not yet accessed at that point. + $this->progress(self::STATUS_INITIALIZED); + } catch (\Throwable $throwable) { + $this->handleFailure($throwable, self::ACTION_FAILED_BUILD); + } finally { + $this->built = true; + } + + return $this; + } + + /** + * @param Module ...$defaultModules Deprecated, use `addModule()` to add default modules. + * @return bool + * + * @throws \Throwable + */ + public function boot(Module ...$defaultModules): bool + { + try { + // Call build() if not called yet, and ensure any new module passed here is added + // as well, throwing if the container was already built. + $this->doBuild(...$defaultModules); + + // Don't allow booting the application multiple times. + $this->assertStatus(self::STATUS_MODULES_ADDED, 'boot application', '<'); + $this->assertStatus(self::STATUS_FAILED, 'boot application', '!='); + + $this->progress(self::STATUS_MODULES_ADDED); + + $this->doExecute(); + + $this->progress(self::STATUS_READY); + + do_action( + $this->hookName(self::ACTION_READY), + $this + ); + } catch (\Throwable $throwable) { + $this->handleFailure($throwable, self::ACTION_FAILED_BOOT); + + return false; + } + + $this->progress(self::STATUS_BOOTED); + + return true; + } + + /** + * @param Module ...$defaultModules + * @return void + */ + private function doBuild(Module ...$defaultModules): void + { + if ($defaultModules) { + $this->deprecatedArgument( + sprintf( + 'Passing default modules to %1$s::boot() is deprecated since version 1.7.0.' + . ' Please add modules via %1$s::addModule().', + __CLASS__ + ), + __METHOD__, + '1.7.0' + ); + } + + if (!$this->built) { + array_map([$this, 'addModule'], $defaultModules); + $this->build(); + + return; + } + + if ( + !$defaultModules + || ($this->status >= self::STATUS_MODULES_ADDED) + || ($this->statusIs(self::STATUS_FAILED)) + ) { + // if we don't have default modules, there's nothing to do, and if the status is beyond + // "modules added" or is failed, we do nothing as well and let `boot()` throw. + return; + } + + $backup = $this->status; + + try { + // simulate idle status to prevent `addModule()` from throwing + // only if we don't have a container yet + $this->hasContainer or $this->status = self::STATUS_IDLE; + + foreach ($defaultModules as $defaultModule) { + // If a module was added by `build()` or `addModule()` we can skip it, a + // deprecation was trigger to make it noticeable without breakage + if (!$this->moduleIs($defaultModule->id(), self::MODULE_ADDED)) { + $this->addModule($defaultModule); + } + } + } finally { + $this->status = $backup; + } + } + + /** + * @param Module $module + * @param string $status + * @return bool + */ + private function addModuleServices(Module $module, string $status): bool + { + $services = null; + $addCallback = null; + switch ($status) { + case self::MODULE_REGISTERED: + $services = $module instanceof ServiceModule ? $module->services() : null; + $addCallback = [$this->containerConfigurator, 'addService']; + break; + case self::MODULE_REGISTERED_FACTORIES: + $services = $module instanceof FactoryModule ? $module->factories() : null; + $addCallback = [$this->containerConfigurator, 'addFactory']; + break; + case self::MODULE_EXTENDED: + $services = $module instanceof ExtendingModule ? $module->extensions() : null; + $addCallback = [$this->containerConfigurator, 'addExtension']; + break; + } + + if (!$services) { + return false; + } + + $ids = []; + array_walk( + $services, + static function (callable $service, string $id) use ($addCallback, &$ids) { + /** @var callable(string, Service|ExtendingService) $addCallback */ + $addCallback($id, $service); + /** @var list $ids */ + $ids[] = $id; + } + ); + /** @var list $ids */ + $this->moduleProgress($module->id(), $status, $ids); + + return true; + } + + /** + * @return void + * + * @throws \Throwable + */ + private function doExecute(): void + { + foreach ($this->executables as $executable) { + $success = $executable->run($this->container()); + $this->moduleProgress( + $executable->id(), + $success + ? self::MODULE_EXECUTED + : self::MODULE_EXECUTION_FAILED + ); + } + } + + /** + * @param string $moduleId + * @param string $status + * @param list|null $serviceIds + * + * @return void + */ + private function moduleProgress(string $moduleId, string $status, ?array $serviceIds = null) + { + isset($this->moduleStatus[$status]) or $this->moduleStatus[$status] = []; + $this->moduleStatus[$status][] = $moduleId; + + if (!$serviceIds || !$this->properties->isDebug()) { + $this->moduleStatus[self::MODULES_ALL][] = "{$moduleId} {$status}"; + + return; + } + + $description = sprintf('%s %s (%s)', $moduleId, $status, implode(', ', $serviceIds)); + $this->moduleStatus[self::MODULES_ALL][] = $description; + } + + /** + * @return array> + */ + public function modulesStatus(): array + { + return $this->moduleStatus; + } + + /** + * @return array + */ + public function connectedPackages(): array + { + return $this->connectedPackages; + } + + /** + * @param string $packageName + * @return bool + */ + public function isPackageConnected(string $packageName): bool + { + return $this->connectedPackages[$packageName] ?? false; + } + + /** + * @param string $moduleId + * @param string $status + * + * @return bool + */ + public function moduleIs(string $moduleId, string $status): bool + { + return in_array($moduleId, $this->moduleStatus[$status] ?? [], true); + } + + /** + * Return the filter name to be used to extend modules of the plugin. + * + * If the plugin is single file `my-plugin.php` in plugins folder the filter name will be: + * `inpsyde.modularity.my-plugin`. + * + * If the plugin is in a sub-folder e.g. `my-plugin/index.php` the filter name will be: + * `inpsyde.modularity.my-plugin` anyway, so the file name is not relevant. + * + * @param string $suffix + * + * @return string + * @see Package::name() + * + */ + public function hookName(string $suffix = ''): string + { + $filter = self::HOOK_PREFIX . $this->properties->baseName(); + + if ($suffix) { + $filter .= '.' . $suffix; + } + + return $filter; + } + + /** + * @return Properties + */ + public function properties(): Properties + { + return $this->properties; + } + + /** + * @return ContainerInterface + * + * @throws \Exception + */ + public function container(): ContainerInterface + { + $this->assertStatus(self::STATUS_INITIALIZED, 'obtain the container instance', '>='); + $this->hasContainer = true; + + return $this->containerConfigurator->createReadOnlyContainer(); + } + + /** + * @return string + */ + public function name(): string + { + return $this->properties->baseName(); + } + + /** + * @param int $status + */ + private function progress(int $status): void + { + $this->status = $status; + } + + /** + * @param int $status + * + * @return bool + */ + public function statusIs(int $status): bool + { + return $this->status === $status; + } + + /** + * @param \Throwable $throwable + * @param Package::ACTION_FAILED_* $action + * @return void + * @throws \Throwable + */ + private function handleFailure(\Throwable $throwable, string $action): void + { + $this->progress(self::STATUS_FAILED); + $hook = $this->hookName($action); + did_action($hook) or do_action($hook, $throwable); + + if ($this->properties->isDebug()) { + throw $throwable; + } + + $this->lastError = $throwable; + } + + /** + * @param int $status + * @param string $action + * @param string $operator + * + * @throws \Exception + * @psalm-suppress ArgumentTypeCoercion + */ + private function assertStatus(int $status, string $action, string $operator = '=='): void + { + if (!version_compare((string) $this->status, (string) $status, $operator)) { + throw new \Exception( + sprintf("Can't %s at this point of application.", $action), + 0, + $this->lastError + ); + } + } + + /** + * Similar to WP's `_deprecated_argument()`, but executes regardless of WP_DEBUG and without + * translated message (so without attempting loading translation files). + * + * @param string $message + * @param string $function + * @param string $version + * + * @return void + */ + private function deprecatedArgument(string $message, string $function, string $version): void + { + do_action('deprecated_argument_run', $function, $message, $version); + + if (apply_filters('deprecated_argument_trigger_error', true)) { + trigger_error($message, \E_USER_DEPRECATED); + } + } +} diff --git a/vendor/inpsyde/modularity/src/Properties/BaseProperties.php b/vendor/inpsyde/modularity/src/Properties/BaseProperties.php new file mode 100644 index 000000000..8bbc730b6 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Properties/BaseProperties.php @@ -0,0 +1,217 @@ +sanitizeBaseName($baseName); + $basePath = (string) trailingslashit($basePath); + if ($baseUrl) { + $baseUrl = (string) trailingslashit($baseUrl); + } + + $this->baseName = $baseName; + $this->basePath = $basePath; + $this->baseUrl = $baseUrl; + $this->properties = array_replace(Properties::DEFAULT_PROPERTIES, $properties); + } + + /** + * @param string $name + * + * @return string + */ + protected function sanitizeBaseName(string $name): string + { + substr_count($name, '/') and $name = dirname($name); + + return strtolower(pathinfo($name, PATHINFO_FILENAME)); + } + + /** + * @return string + */ + public function baseName(): string + { + return $this->baseName; + } + + /** + * @return string + */ + public function basePath(): string + { + return $this->basePath; + } + + /** + * @return string|null + */ + public function baseUrl(): ?string + { + return $this->baseUrl; + } + + /** + * @return string + */ + public function author(): string + { + return (string) $this->get(self::PROP_AUTHOR); + } + + /** + * @return string + */ + public function authorUri(): string + { + return (string) $this->get(self::PROP_AUTHOR_URI); + } + + /** + * @return string + */ + public function description(): string + { + return (string) $this->get(self::PROP_DESCRIPTION); + } + + /** + * @return string + */ + public function textDomain(): string + { + return (string) $this->get(self::PROP_TEXTDOMAIN); + } + + /** + * @return string + */ + public function domainPath(): string + { + return (string) $this->get(self::PROP_DOMAIN_PATH); + } + + /** + * @return string + */ + public function name(): string + { + return (string) $this->get(self::PROP_NAME); + } + + /** + * @return string + */ + public function uri(): string + { + return (string) $this->get(self::PROP_URI); + } + + /** + * @return string + */ + public function version(): string + { + return (string) $this->get(self::PROP_VERSION); + } + + /** + * @return string|null + */ + public function requiresWp(): ?string + { + $value = $this->get(self::PROP_REQUIRES_WP); + + return $value && is_string($value) ? $value : null; + } + + /** + * @return string|null + */ + public function requiresPhp(): ?string + { + $value = $this->get(self::PROP_REQUIRES_PHP); + + return $value && is_string($value) ? $value : null; + } + + /** + * @return array + */ + public function tags(): array + { + return (array) $this->get(self::PROP_TAGS); + } + + /** + * @param string $key + * @param null $default + * @return mixed + */ + public function get(string $key, $default = null) + { + return $this->properties[$key] ?? $default; + } + + /** + * @param string $key + * @return bool + */ + public function has(string $key): bool + { + return isset($this->properties[$key]); + } + + /** + * @return bool + * @see Properties::isDebug() + */ + public function isDebug(): bool + { + if ($this->isDebug === null) { + $this->isDebug = defined('WP_DEBUG') && WP_DEBUG; + } + + return $this->isDebug; + } +} diff --git a/vendor/inpsyde/modularity/src/Properties/LibraryProperties.php b/vendor/inpsyde/modularity/src/Properties/LibraryProperties.php new file mode 100644 index 000000000..77539dd81 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Properties/LibraryProperties.php @@ -0,0 +1,209 @@ + 0) { + $properties[self::PROP_AUTHOR] = implode(', ', $names); + } + + // Custom settings which can be stored in composer.json "extra.modularity" + $extra = $composerJsonData['extra']['modularity'] ?? []; + foreach (self::EXTRA_KEYS as $key) { + $properties[$key] = $extra[$key] ?? ''; + } + + // PHP requirement in composer.json "require" or "require-dev" + $properties[self::PROP_REQUIRES_PHP] = self::extractPhpVersion($composerJsonData); + + // composer.json might have "version" in root + $version = $composerJsonData['version'] ?? null; + if ($version && is_string($version)) { + $properties[self::PROP_VERSION] = $version; + } + + [$baseName, $name] = static::buildNames($composerJsonData); + $basePath = dirname($composerJsonFile); + if (empty($properties[self::PROP_NAME])) { + $properties[self::PROP_NAME] = $name; + } + + return new self( + $baseName, + $basePath, + $baseUrl, + $properties + ); + } + + /** + * @param array $composerJsonData + * + * @return array{string, string} + */ + private static function buildNames(array $composerJsonData): array + { + $composerName = (string) ($composerJsonData['name'] ?? ''); + $packageNamePieces = explode('/', $composerName, 2); + $basename = implode('-', $packageNamePieces); + // "inpsyde/foo-bar-baz" => "Inpsyde Foo Bar Baz" + $name = mb_convert_case( + str_replace(['-', '_', '.'], ' ', implode(' ', $packageNamePieces)), + MB_CASE_TITLE + ); + + return [$basename, $name]; + } + + /** + * Check PHP version in require, require-dev. + * + * Attempt to parse requirements to find the _minimum_ accepted version (consistent with WP). + * Composer requirements are parsed in a way that, for example: + * `>=7.2` returns `7.2` + * `^7.3` returns `7.3` + * `5.6 || >= 7.1` returns `5.6` + * `>= 7.1 < 8` returns `7.1` + * + * @param array $composerData + * @param string $key + * + * @return string|null + */ + private static function extractPhpVersion(array $composerData, string $key = 'require'): ?string + { + $nextKey = ($key === 'require') + ? 'require-dev' + : null; + $base = (array) ($composerData[$key] ?? []); + $requirement = $base['php'] ?? null; + $version = ($requirement && is_string($requirement)) + ? trim($requirement) + : null; + if (!$version) { + return $nextKey + ? static::extractPhpVersion($composerData, $nextKey) + : null; + } + + static $matcher; + $matcher or $matcher = static function (string $version): ?string { + $version = trim($version); + if (!$version) { + return null; + } + + // versions range like `>= 7.2.4 < 8` + if (preg_match('{>=?([\s0-9\.]+)<}', $version, $matches)) { + return trim($matches[1], " \t\n\r\0\x0B."); + } + + // aliases like `dev-src#abcde as 7.4` + if (preg_match('{as\s*([\s0-9\.]+)}', $version, $matches)) { + return trim($matches[1], " \t\n\r\0\x0B."); + } + + // Basic requirements like 7.2, >=7.2, ^7.2, ~7.2 + if (preg_match('{^(?:[>=\s~\^]+)?([0-9\.]+)}', $version, $matches)) { + return trim($matches[1], " \t\n\r\0\x0B."); + } + + return null; + }; + + // support for simpler requirements like `7.3`, `>=7.4` or alternative like `5.6 || >=7` + + $alternatives = explode('||', $version); + $found = null; + foreach ($alternatives as $alternative) { + /** @var callable(string):?string $matcher */ + $itemFound = $matcher($alternative); + if ($itemFound && (!$found || version_compare($itemFound, $found, '<'))) { + $found = $itemFound; + } + } + + if ($found) { + return $found; + } + + return $nextKey + ? static::extractPhpVersion($composerData, $nextKey) + : null; + } + + /** + * @param string $url + * + * @return static + * + * @throws \Exception + */ + public function withBaseUrl(string $url): LibraryProperties + { + if ($this->baseUrl !== null) { + throw new \Exception(sprintf('%s::$baseUrl property is not overridable.', __CLASS__)); + } + + $this->baseUrl = trailingslashit($url); + + return $this; + } +} diff --git a/vendor/inpsyde/modularity/src/Properties/PluginProperties.php b/vendor/inpsyde/modularity/src/Properties/PluginProperties.php new file mode 100644 index 000000000..050abd3d2 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Properties/PluginProperties.php @@ -0,0 +1,190 @@ + 'Author', + self::PROP_AUTHOR_URI => 'AuthorURI', + self::PROP_DESCRIPTION => 'Description', + self::PROP_DOMAIN_PATH => 'DomainPath', + self::PROP_NAME => 'Name', + self::PROP_TEXTDOMAIN => 'TextDomain', + self::PROP_URI => 'PluginURI', + self::PROP_VERSION => 'Version', + self::PROP_REQUIRES_WP => 'RequiresWP', + self::PROP_REQUIRES_PHP => 'RequiresPHP', + + // additional headers + self::PROP_NETWORK => 'Network', + self::PROP_REQUIRES_PLUGINS => 'RequiresPlugins', + ]; + + /** + * @var string + */ + private $pluginMainFile; + + /** + * @var string + */ + private $pluginBaseName; + + /** + * @var bool|null + */ + protected $isMu; + + /** + * @var bool|null + */ + protected $isActive; + + /** + * @var bool|null + */ + protected $isNetworkActive; + + /** + * @param string $pluginMainFile + * + * @return PluginProperties + */ + public static function new(string $pluginMainFile): PluginProperties + { + return new self($pluginMainFile); + } + + /** + * PluginProperties constructor. + * + * @param string $pluginMainFile + */ + protected function __construct(string $pluginMainFile) + { + if (!function_exists('get_plugin_data')) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + // $markup = false, to avoid an incorrect early wptexturize call. Also we probably don't want HTML here anyway + // @see https://core.trac.wordpress.org/ticket/49965 + $pluginData = get_plugin_data($pluginMainFile, false); + $properties = Properties::DEFAULT_PROPERTIES; + + // Map pluginData to internal structure. + foreach (self::HEADERS as $key => $pluginDataKey) { + $properties[$key] = $pluginData[$pluginDataKey] ?? ''; + unset($pluginData[$pluginDataKey]); + } + $properties = array_merge($properties, $pluginData); + + $this->pluginMainFile = wp_normalize_path($pluginMainFile); + + $this->pluginBaseName = plugin_basename($pluginMainFile); + $basePath = plugin_dir_path($pluginMainFile); + $baseUrl = plugins_url('/', $pluginMainFile); + + parent::__construct( + $this->pluginBaseName, + $basePath, + $baseUrl, + $properties + ); + } + + /** + * @return string + */ + public function pluginMainFile(): string + { + return $this->pluginMainFile; + } + + /** + * @return bool + * + * @psalm-suppress PossiblyFalseArgument + */ + public function network(): bool + { + return (bool) $this->get(self::PROP_NETWORK, false); + } + + /** + * @return array + */ + public function requiresPlugins(): array + { + $value = $this->get(self::PROP_REQUIRES_PLUGINS); + + return $value && is_string($value) ? explode(',', $value) : []; + } + + /** + * @return bool + */ + public function isActive(): bool + { + if ($this->isActive === null) { + if (!function_exists('is_plugin_active')) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + $this->isActive = is_plugin_active($this->pluginBaseName); + } + + return $this->isActive; + } + + /** + * @return bool + */ + public function isNetworkActive(): bool + { + if ($this->isNetworkActive === null) { + if (!function_exists('is_plugin_active_for_network')) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + $this->isNetworkActive = is_plugin_active_for_network($this->pluginBaseName); + } + + return $this->isNetworkActive; + } + + /** + * @return bool + */ + public function isMuPlugin(): bool + { + if ($this->isMu === null) { + /** + * @psalm-suppress UndefinedConstant + * @psalm-suppress MixedArgument + */ + $muPluginDir = wp_normalize_path(WPMU_PLUGIN_DIR); + $this->isMu = strpos($this->pluginMainFile, $muPluginDir) === 0; + } + + return $this->isMu; + } +} diff --git a/vendor/inpsyde/modularity/src/Properties/Properties.php b/vendor/inpsyde/modularity/src/Properties/Properties.php new file mode 100644 index 000000000..0efed8da6 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Properties/Properties.php @@ -0,0 +1,139 @@ + '', + self::PROP_AUTHOR_URI => '', + self::PROP_DESCRIPTION => '', + self::PROP_DOMAIN_PATH => '', + self::PROP_NAME => '', + self::PROP_TEXTDOMAIN => '', + self::PROP_URI => '', + self::PROP_VERSION => '', + self::PROP_REQUIRES_WP => null, + self::PROP_REQUIRES_PHP => null, + self::PROP_TAGS => [], + ]; + + /** + * @param string $key + * @param null $default + * + * @return mixed + */ + public function get(string $key, $default = null); + + /** + * @param string $key + * + * @return bool + */ + public function has(string $key): bool; + + /** + * @return bool + */ + public function isDebug(): bool; + + /** + * @return string + */ + public function baseName(): string; + + /** + * @return string + */ + public function basePath(): string; + + /** + * @return string|null + */ + public function baseUrl(): ?string; + + /** + * @return string + */ + public function author(): string; + + /** + * @return string + */ + public function authorUri(): string; + + /** + * @return string + */ + public function description(): string; + + /** + * @return string + */ + public function textDomain(): string; + + /** + * @return string + */ + public function domainPath(): string; + + /** + * The name of the plugin, theme or library. + * + * @return string + */ + public function name(): string; + + /** + * The home page of the plugin, theme or library. + * @return string + */ + public function uri(): string; + + /** + * @return string + */ + public function version(): string; + + /** + * Optional. Specify the minimum required WordPress version. + * + * @return string|null + */ + public function requiresWp(): ?string; + + /** + * Optional. Specify the minimum required PHP version. + * + * @return string + */ + public function requiresPhp(): ?string; + + /** + * Optional. Currently, only available for Theme and Library. + * Plugins do not have support for "tags"/"keywords" in header. + * + * @link https://developer.wordpress.org/reference/classes/wp_theme/#properties + * @link https://getcomposer.org/doc/04-schema.md#keywords + * + * @return array + */ + public function tags(): array; +} diff --git a/vendor/inpsyde/modularity/src/Properties/ThemeProperties.php b/vendor/inpsyde/modularity/src/Properties/ThemeProperties.php new file mode 100644 index 000000000..b62060998 --- /dev/null +++ b/vendor/inpsyde/modularity/src/Properties/ThemeProperties.php @@ -0,0 +1,131 @@ + 'Author', + self::PROP_AUTHOR_URI => 'AuthorURI', + self::PROP_DESCRIPTION => 'Description', + self::PROP_DOMAIN_PATH => 'DomainPath', + self::PROP_NAME => 'Name', + self::PROP_TEXTDOMAIN => 'TextDomain', + self::PROP_URI => 'ThemeURI', + self::PROP_VERSION => 'Version', + self::PROP_REQUIRES_WP => 'RequiresWP', + self::PROP_REQUIRES_PHP => 'RequiresPHP', + + // additional headers + self::PROP_STATUS => 'Status', + self::PROP_TAGS => 'Tags', + self::PROP_TEMPLATE => 'Template', + ]; + + /** + * @param string $themeDirectory + * + * @return ThemeProperties + */ + public static function new(string $themeDirectory): ThemeProperties + { + return new self($themeDirectory); + } + + /** + * ThemeProperties constructor. + * + * @param string $themeDirectory + */ + protected function __construct(string $themeDirectory) + { + if (!function_exists('wp_get_theme')) { + require_once ABSPATH . 'wp-includes/theme.php'; + } + + $theme = wp_get_theme($themeDirectory); + $properties = Properties::DEFAULT_PROPERTIES; + + foreach (self::HEADERS as $key => $themeKey) { + /** @psalm-suppress DocblockTypeContradiction */ + $properties[$key] = $theme->get($themeKey) ?? ''; + } + + $baseName = $theme->get_stylesheet(); + $basePath = $theme->get_stylesheet_directory(); + $baseUrl = (string) trailingslashit($theme->get_stylesheet_directory_uri()); + + parent::__construct( + $baseName, + $basePath, + $baseUrl, + $properties + ); + } + + /** + * If the theme is published. + * + * @return string + */ + public function status(): string + { + return (string) $this->get(self::PROP_STATUS); + } + + public function template(): string + { + return (string) $this->get(self::PROP_TEMPLATE); + } + + /** + * @return bool + */ + public function isChildTheme(): bool + { + return (bool) $this->template(); + } + + /** + * @return bool + */ + public function isCurrentTheme(): bool + { + return get_stylesheet() === $this->baseName(); + } + + /** + * @return ThemeProperties|null + */ + public function parentThemeProperties(): ?ThemeProperties + { + $template = $this->template(); + if (!$template) { + return null; + } + + $parent = wp_get_theme($template, get_theme_root($template)); + + return static::new($parent->get_template_directory()); + } +} diff --git a/vendor/inpsyde/wp-context/LICENSE b/vendor/inpsyde/wp-context/LICENSE new file mode 100644 index 000000000..28fbecabf --- /dev/null +++ b/vendor/inpsyde/wp-context/LICENSE @@ -0,0 +1,361 @@ +### GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +### Preamble + +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the +original, so that any problems introduced by others will not reflect +on the original authors' reputations. + +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at +all. + +The precise terms and conditions for copying, distribution and +modification follow. + +### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +**0.** This License applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work +based on the Program" means either the Program or any derivative work +under copyright law: that is to say, a work containing the Program or +a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is +included without limitation in the term "modification".) Each licensee +is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether that +is true depends on what the Program does. + +**1.** You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a +fee. + +**2.** You may modify your copy or copies of the Program or any +portion of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + +**a)** You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + + +**b)** You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any part +thereof, to be licensed as a whole at no charge to all third parties +under the terms of this License. + + +**c)** If the modified program normally reads commands interactively +when run, you must cause it, when started running for such interactive +use in the most ordinary way, to print or display an announcement +including an appropriate copyright notice and a notice that there is +no warranty (or else, saying that you provide a warranty) and that +users may redistribute the program under these conditions, and telling +the user how to view a copy of this License. (Exception: if the +Program itself is interactive but does not normally print such an +announcement, your work based on the Program is not required to print +an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +**3.** You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + +**a)** Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange; or, + + +**b)** Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your cost of +physically performing source distribution, a complete machine-readable +copy of the corresponding source code, to be distributed under the +terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or, + + +**c)** Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is allowed +only for noncommercial distribution and only if you received the +program in object code or executable form with such an offer, in +accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +**4.** You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and +will automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. + +**5.** You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +**6.** Each time you redistribute the Program (or any work based on +the Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +**7.** If, as a consequence of a court judgment or allegation of +patent infringement or for any other reason (not limited to patent +issues), conditions are imposed on you (whether by court order, +agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. +If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, +then as a consequence you may not distribute the Program at all. For +example, if a patent license would not permit royalty-free +redistribution of the Program by all those who receive copies directly +or indirectly through you, then the only way you could satisfy both it +and this License would be to refrain entirely from distribution of the +Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +**8.** If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +**9.** The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation. + +**10.** If you wish to incorporate parts of the Program into other +free programs whose distribution conditions are different, write to +the author to ask for permission. For software which is copyrighted by +the Free Software Foundation, write to the Free Software Foundation; +we sometimes make exceptions for this. Our decision will be guided by +the two goals of preserving the free status of all derivatives of our +free software and of promoting the sharing and reuse of software +generally. + +**NO WARRANTY** + +**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +### END OF TERMS AND CONDITIONS + +### How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + one line to give the program's name and an idea of what it does. + Copyright (C) yyyy name of author + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper +mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details + type `show w'. This is free software, and you are welcome + to redistribute it under certain conditions; type `show c' + for details. + +The hypothetical commands \`show w' and \`show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than \`show w' and +\`show c'; they could even be mouse-clicks or menu items--whatever +suits your program. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the program, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright + interest in the program `Gnomovision' + (which makes passes at compilers) written + by James Hacker. + + signature of Ty Coon, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, +you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +[GNU Lesser General Public +License](https://www.gnu.org/licenses/lgpl.html) instead of this +License. diff --git a/vendor/inpsyde/wp-context/composer.json b/vendor/inpsyde/wp-context/composer.json new file mode 100644 index 000000000..e96ed0db1 --- /dev/null +++ b/vendor/inpsyde/wp-context/composer.json @@ -0,0 +1,68 @@ +{ + "name": "inpsyde/wp-context", + "type": "library", + "description": "A single-class utility to check the running context in WordPress sites.", + "license": "gpl-2.0-or-later", + "authors": [ + { + "name": "Inpsyde GmbH", + "homepage": "https://inpsyde.com/", + "email": "hello@inpsyde.com", + "role": "Company" + }, + { + "name": "Giuseppe Mazzapica", + "email": "g.mazzapica@inpsyde.com", + "role": "Developer" + } + ], + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "~7.5.20 || ^8", + "inpsyde/php-coding-standards": "^1", + "vimeo/psalm": "^4.27.0", + "mockery/mockery": "~1.3.6", + "brain/monkey": "^2.6.1", + "inpsyde/wp-stubs": "dev-main" + }, + "autoload": { + "psr-4": { + "Inpsyde\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Inpsyde\\Tests\\": "tests/" + } + }, + "minimum-stability": "dev", + "prefer-stable": true, + "scripts": { + "cs": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs", + "psalm": "@php ./vendor/vimeo/psalm/psalm --no-cache --output-format=compact", + "tests": "@php ./vendor/phpunit/phpunit/phpunit", + "tests:no-cov": "@php ./vendor/phpunit/phpunit/phpunit --no-coverage", + "phpcompat": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs -p . --standard=PHPCompatibility --ignore=*/vendor/* --extensions=php --basepath=./ --runtime-set testVersion 7.1-", + "qa": [ + "@cs", + "@phpcompat", + "@psalm", + "@tests:no-cov" + ] + }, + "config": { + "optimize-autoloader": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "inpsyde/*": true, + "composer/*": true + } + }, + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + } +} diff --git a/vendor/inpsyde/wp-context/src/WpContext.php b/vendor/inpsyde/wp-context/src/WpContext.php new file mode 100644 index 000000000..0962c164a --- /dev/null +++ b/vendor/inpsyde/wp-context/src/WpContext.php @@ -0,0 +1,403 @@ + + */ + private $actionCallbacks = []; + + /** + * @return WpContext + */ + final public static function new(): WpContext + { + return new self(array_fill_keys(self::ALL, false)); + } + + /** + * @return WpContext + */ + final public static function determine(): WpContext + { + /** @psalm-suppress RedundantCondition */ + $installing = defined('WP_INSTALLING') && WP_INSTALLING; + /** @psalm-suppress RedundantCondition */ + $xmlRpc = defined('XMLRPC_REQUEST') && XMLRPC_REQUEST; + $isCore = defined('ABSPATH'); + $isCli = defined('WP_CLI'); + $notInstalling = $isCore && !$installing; + $isAjax = $notInstalling && wp_doing_ajax(); + $isAdmin = $notInstalling && is_admin() && !$isAjax; + $isCron = $notInstalling && wp_doing_cron(); + $isWpActivate = $installing && is_multisite() && self::isWpActivateRequest(); + + $undetermined = $notInstalling && !$isAdmin && !$isCron && !$isCli && !$xmlRpc && !$isAjax; + + $isRest = $undetermined && static::isRestRequest(); + $isLogin = $undetermined && !$isRest && static::isLoginRequest(); + + // When nothing else matches, we assume it is a front-office request. + $isFront = $undetermined && !$isRest && !$isLogin; + + /* + * Note that when core is installing **only** `INSTALLING` will be true, not even `CORE`. + * This is done to do as less as possible during installation, when most of WP does not act + * as expected. + */ + + $instance = new self( + [ + self::AJAX => $isAjax, + self::BACKOFFICE => $isAdmin, + self::CLI => $isCli, + self::CORE => ($isCore || $xmlRpc) && (!$installing || $isWpActivate), + self::CRON => $isCron, + self::FRONTOFFICE => $isFront, + self::INSTALLING => $installing && !$isWpActivate, + self::LOGIN => $isLogin, + self::REST => $isRest, + self::XML_RPC => $xmlRpc && !$installing, + self::WP_ACTIVATE => $isWpActivate, + ] + ); + + $instance->addActionHooks(); + + return $instance; + } + + /** + * @return bool + */ + private static function isRestRequest(): bool + { + if ( + (defined('REST_REQUEST') && REST_REQUEST) + || !empty($_GET['rest_route']) // phpcs:ignore + ) { + return true; + } + + if (!get_option('permalink_structure')) { + return false; + } + + /* + * This is needed because, if called early, global $wp_rewrite is not defined but required + * by get_rest_url(). WP will reuse what we set here, or in worst case will replace, but no + * consequences for us in any case. + */ + if (empty($GLOBALS['wp_rewrite'])) { + $GLOBALS['wp_rewrite'] = new \WP_Rewrite(); + } + + $currentPath = trim((string)parse_url((string)add_query_arg([]), PHP_URL_PATH), '/') . '/'; + $restPath = trim((string)parse_url((string)get_rest_url(), PHP_URL_PATH), '/') . '/'; + + return strpos($currentPath, $restPath) === 0; + } + + /** + * @return bool + */ + private static function isLoginRequest(): bool + { + /** + * New core function with WordPress 6.1 + * @link https://make.wordpress.org/core/2022/09/11/new-is_login-function-for-determining-if-a-page-is-the-login-screen/ + */ + if (function_exists('is_login')) { + return is_login() !== false; + } + + if (!empty($_REQUEST['interim-login'])) { // phpcs:ignore + return true; + } + + /** + * Fallback and 1:1 copy from is_login() in case, the function is + * not available for WP < 6.1. + * phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotValidated + * phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash + * phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + */ + $scriptName = $_SERVER['SCRIPT_NAME'] ?? ''; + + return false !== stripos(wp_login_url(), $scriptName); + } + + /** + * @return bool + */ + private static function isWpActivateRequest(): bool + { + return static::isPageNow('wp-activate.php', network_site_url('wp-activate.php')); + } + + /** + * @param string $page + * @param string $url + * @return bool + */ + private static function isPageNow(string $page, string $url): bool + { + $pageNow = (string)($GLOBALS['pagenow'] ?? ''); + if ($pageNow && (basename($pageNow) === $page)) { + return true; + } + + $currentPath = (string)parse_url(add_query_arg([]), PHP_URL_PATH); + $targetPath = (string)parse_url($url, PHP_URL_PATH); + + return trim($currentPath, '/') === trim($targetPath, '/'); + } + + /** + * @param array $data + */ + private function __construct(array $data) + { + $this->data = $data; + } + + /** + * @param string $context + * @return WpContext + */ + final public function force(string $context): WpContext + { + if (!in_array($context, self::ALL, true)) { + throw new \LogicException("'{$context}' is not a valid context."); + } + + $this->removeActionHooks(); + + $data = array_fill_keys(self::ALL, false); + $data[$context] = true; + if (!in_array($context, [self::INSTALLING, self::CLI, self::CORE], true)) { + $data[self::CORE] = true; + } + + $this->data = $data; + + return $this; + } + + /** + * @return WpContext + */ + final public function withCli(): WpContext + { + $this->data[self::CLI] = true; + + return $this; + } + + /** + * @param string $context + * @param string ...$contexts + * @return bool + */ + final public function is(string $context, string ...$contexts): bool + { + array_unshift($contexts, $context); + + foreach ($contexts as $context) { + if (($this->data[$context] ?? null)) { + return true; + } + } + + return false; + } + + /** + * @return bool + */ + public function isCore(): bool + { + return $this->is(self::CORE); + } + + /** + * @return bool + */ + public function isFrontoffice(): bool + { + return $this->is(self::FRONTOFFICE); + } + + /** + * @return bool + */ + public function isBackoffice(): bool + { + return $this->is(self::BACKOFFICE); + } + + /** + * @return bool + */ + public function isAjax(): bool + { + return $this->is(self::AJAX); + } + + /** + * @return bool + */ + public function isLogin(): bool + { + return $this->is(self::LOGIN); + } + + /** + * @return bool + */ + public function isRest(): bool + { + return $this->is(self::REST); + } + + /** + * @return bool + */ + public function isCron(): bool + { + return $this->is(self::CRON); + } + + /** + * @return bool + */ + public function isWpCli(): bool + { + return $this->is(self::CLI); + } + + /** + * @return bool + */ + public function isXmlRpc(): bool + { + return $this->is(self::XML_RPC); + } + + /** + * @return bool + */ + public function isInstalling(): bool + { + return $this->is(self::INSTALLING); + } + + /** + * @return bool + */ + public function isWpActivate(): bool + { + return $this->is(self::WP_ACTIVATE); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + return $this->data; + } + + /** + * When context is determined very early we do our best to understand some context like + * login, rest and front-office even if WordPress normally would require a later hook. + * When that later hook happen, we change what we have determined, leveraging the more + * "core-compliant" approach. + * + * @return void + */ + private function addActionHooks(): void + { + $this->actionCallbacks = [ + 'login_init' => function (): void { + $this->resetAndForce(self::LOGIN); + }, + 'rest_api_init' => function (): void { + $this->resetAndForce(self::REST); + }, + 'activate_header' => function (): void { + $this->resetAndForce(self::WP_ACTIVATE); + }, + 'template_redirect' => function (): void { + $this->resetAndForce(self::FRONTOFFICE); + }, + 'current_screen' => function (\WP_Screen $screen): void { + $screen->in_admin() and $this->resetAndForce(self::BACKOFFICE); + }, + ]; + + foreach ($this->actionCallbacks as $action => $callback) { + add_action($action, $callback, PHP_INT_MIN); + } + } + + /** + * When "force" is called on an instance created via `determine()` we need to remove added hooks + * or what we are forcing might be overridden. + * + * @return void + */ + private function removeActionHooks(): void + { + foreach ($this->actionCallbacks as $action => $callback) { + remove_action($action, $callback, PHP_INT_MIN); + } + $this->actionCallbacks = []; + } + + /** + * @param string $context + * @return void + */ + private function resetAndForce(string $context): void + { + $cli = $this->isWpCli(); + $this->force($context); + $cli and $this->withCli(); + } +} diff --git a/vendor/psr/container/.gitignore b/vendor/psr/container/.gitignore new file mode 100644 index 000000000..b2395aa05 --- /dev/null +++ b/vendor/psr/container/.gitignore @@ -0,0 +1,3 @@ +composer.lock +composer.phar +/vendor/ diff --git a/vendor/psr/container/LICENSE b/vendor/psr/container/LICENSE new file mode 100644 index 000000000..2877a4894 --- /dev/null +++ b/vendor/psr/container/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2016 container-interop +Copyright (c) 2016 PHP Framework Interoperability Group + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/psr/container/README.md b/vendor/psr/container/README.md new file mode 100644 index 000000000..1b9d9e570 --- /dev/null +++ b/vendor/psr/container/README.md @@ -0,0 +1,13 @@ +Container interface +============== + +This repository holds all interfaces related to [PSR-11 (Container Interface)][psr-url]. + +Note that this is not a Container implementation of its own. It is merely abstractions that describe the components of a Dependency Injection Container. + +The installable [package][package-url] and [implementations][implementation-url] are listed on Packagist. + +[psr-url]: https://www.php-fig.org/psr/psr-11/ +[package-url]: https://packagist.org/packages/psr/container +[implementation-url]: https://packagist.org/providers/psr/container-implementation + diff --git a/vendor/psr/container/composer.json b/vendor/psr/container/composer.json new file mode 100644 index 000000000..baf6cd1a0 --- /dev/null +++ b/vendor/psr/container/composer.json @@ -0,0 +1,27 @@ +{ + "name": "psr/container", + "type": "library", + "description": "Common Container Interface (PHP FIG PSR-11)", + "keywords": ["psr", "psr-11", "container", "container-interop", "container-interface"], + "homepage": "https://github.com/php-fig/container", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=7.4.0" + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + } +} diff --git a/vendor/psr/container/src/ContainerExceptionInterface.php b/vendor/psr/container/src/ContainerExceptionInterface.php new file mode 100644 index 000000000..0f213f2fe --- /dev/null +++ b/vendor/psr/container/src/ContainerExceptionInterface.php @@ -0,0 +1,12 @@ +=7.2.0" + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/vendor/psr/event-dispatcher/src/EventDispatcherInterface.php b/vendor/psr/event-dispatcher/src/EventDispatcherInterface.php new file mode 100644 index 000000000..4306fa915 --- /dev/null +++ b/vendor/psr/event-dispatcher/src/EventDispatcherInterface.php @@ -0,0 +1,21 @@ +logger = $logger; + } + + public function doSomething() + { + if ($this->logger) { + $this->logger->info('Doing work'); + } + + try { + $this->doSomethingElse(); + } catch (Exception $exception) { + $this->logger->error('Oh no!', array('exception' => $exception)); + } + + // do something useful + } +} +``` + +You can then pick one of the implementations of the interface to get a logger. + +If you want to implement the interface, you can require this package and +implement `Psr\Log\LoggerInterface` in your code. Please read the +[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +for details. diff --git a/vendor/psr/log/composer.json b/vendor/psr/log/composer.json new file mode 100644 index 000000000..879fc6f53 --- /dev/null +++ b/vendor/psr/log/composer.json @@ -0,0 +1,26 @@ +{ + "name": "psr/log", + "description": "Common interface for logging libraries", + "keywords": ["psr", "psr-3", "log"], + "homepage": "https://github.com/php-fig/log", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=8.0.0" + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + } +} diff --git a/vendor/psr/log/src/AbstractLogger.php b/vendor/psr/log/src/AbstractLogger.php new file mode 100644 index 000000000..d60a091af --- /dev/null +++ b/vendor/psr/log/src/AbstractLogger.php @@ -0,0 +1,15 @@ +logger = $logger; + } +} diff --git a/vendor/psr/log/src/LoggerInterface.php b/vendor/psr/log/src/LoggerInterface.php new file mode 100644 index 000000000..b3a24b5f7 --- /dev/null +++ b/vendor/psr/log/src/LoggerInterface.php @@ -0,0 +1,125 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function alert(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function critical(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function error(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function warning(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function notice(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function info(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function debug(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::DEBUG, $message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string|\Stringable $message + * @param array $context + * + * @return void + * + * @throws \Psr\Log\InvalidArgumentException + */ + abstract public function log($level, string|\Stringable $message, array $context = []): void; +} diff --git a/vendor/psr/log/src/NullLogger.php b/vendor/psr/log/src/NullLogger.php new file mode 100644 index 000000000..c1cc3c069 --- /dev/null +++ b/vendor/psr/log/src/NullLogger.php @@ -0,0 +1,30 @@ +logger) { }` + * blocks. + */ +class NullLogger extends AbstractLogger +{ + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string|\Stringable $message + * @param array $context + * + * @return void + * + * @throws \Psr\Log\InvalidArgumentException + */ + public function log($level, string|\Stringable $message, array $context = []): void + { + // noop + } +} diff --git a/vendor/psr/simple-cache/.editorconfig b/vendor/psr/simple-cache/.editorconfig new file mode 100644 index 000000000..48542cbb4 --- /dev/null +++ b/vendor/psr/simple-cache/.editorconfig @@ -0,0 +1,12 @@ +; This file is for unifying the coding style for different editors and IDEs. +; More information at http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_size = 4 +indent_style = space +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/vendor/psr/simple-cache/LICENSE.md b/vendor/psr/simple-cache/LICENSE.md new file mode 100644 index 000000000..e49a7c85a --- /dev/null +++ b/vendor/psr/simple-cache/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) 2016 PHP Framework Interoperability Group + +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +> THE SOFTWARE. diff --git a/vendor/psr/simple-cache/README.md b/vendor/psr/simple-cache/README.md new file mode 100644 index 000000000..43641d175 --- /dev/null +++ b/vendor/psr/simple-cache/README.md @@ -0,0 +1,8 @@ +PHP FIG Simple Cache PSR +======================== + +This repository holds all interfaces related to PSR-16. + +Note that this is not a cache implementation of its own. It is merely an interface that describes a cache implementation. See [the specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md) for more details. + +You can find implementations of the specification by looking for packages providing the [psr/simple-cache-implementation](https://packagist.org/providers/psr/simple-cache-implementation) virtual package. diff --git a/vendor/psr/simple-cache/composer.json b/vendor/psr/simple-cache/composer.json new file mode 100644 index 000000000..f307a8456 --- /dev/null +++ b/vendor/psr/simple-cache/composer.json @@ -0,0 +1,25 @@ +{ + "name": "psr/simple-cache", + "description": "Common interfaces for simple caching", + "keywords": ["psr", "psr-16", "cache", "simple-cache", "caching"], + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=8.0.0" + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + } +} diff --git a/vendor/psr/simple-cache/src/CacheException.php b/vendor/psr/simple-cache/src/CacheException.php new file mode 100644 index 000000000..f61b24c2b --- /dev/null +++ b/vendor/psr/simple-cache/src/CacheException.php @@ -0,0 +1,10 @@ + $keys A list of keys that can be obtained in a single operation. + * @param mixed $default Default value to return for keys that do not exist. + * + * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + public function getMultiple(iterable $keys, mixed $default = null): iterable; + + /** + * Persists a set of key => value pairs in the cache, with an optional TTL. + * + * @param iterable $values A list of key => value pairs for a multiple-set operation. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * + * @return bool True on success and false on failure. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $values is neither an array nor a Traversable, + * or if any of the $values are not a legal value. + */ + public function setMultiple(iterable $values, null|int|\DateInterval $ttl = null): bool; + + /** + * Deletes multiple cache items in a single operation. + * + * @param iterable $keys A list of string-based keys to be deleted. + * + * @return bool True if the items were successfully removed. False if there was an error. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + public function deleteMultiple(iterable $keys): bool; + + /** + * Determines whether an item is present in the cache. + * + * NOTE: It is recommended that has() is only to be used for cache warming type purposes + * and not to be used within your live applications operations for get/set, as this method + * is subject to a race condition where your has() will return true and immediately after, + * another script can remove it making the state of your app out of date. + * + * @param string $key The cache item key. + * + * @return bool + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + */ + public function has(string $key): bool; +} diff --git a/vendor/psr/simple-cache/src/InvalidArgumentException.php b/vendor/psr/simple-cache/src/InvalidArgumentException.php new file mode 100644 index 000000000..6a9524a20 --- /dev/null +++ b/vendor/psr/simple-cache/src/InvalidArgumentException.php @@ -0,0 +1,13 @@ +> $GITHUB_ENV) && (echo "No changes to commit")) + + - name: Git push to "main" branch + if: ${{ env.CHANGES == 'yes' }} + run: git push + + - name: Move tag + if: ${{ github.ref_type == 'tag'}} + run: | + git tag -d ${{ github.ref_name }} + git push origin :refs/tags/${{ github.ref_name }} + git tag ${{ github.ref_name }} + git push origin --tags + diff --git a/vendor/rrze/fau-studium-common/.github/workflows/quality-assurance-php.yml b/vendor/rrze/fau-studium-common/.github/workflows/quality-assurance-php.yml new file mode 100644 index 000000000..c1daba9ef --- /dev/null +++ b/vendor/rrze/fau-studium-common/.github/workflows/quality-assurance-php.yml @@ -0,0 +1,40 @@ +name: Quality assurance PHP +on: + pull_request: + branches: + - main + - dev + paths: + - '**.php' + - 'composer.*' + - 'phpcs.*' + - 'phpunit.*' + - 'psalm.*' +jobs: + coding-standards-analysis-php: + uses: inpsyde/reusable-workflows/.github/workflows/coding-standards-php.yml@main + secrets: + COMPOSER_AUTH_JSON: ${{ secrets.PACKAGIST_AUTH_JSON }} + with: + PHP_VERSION: "8.0" + static-code-analysis-php: + uses: inpsyde/reusable-workflows/.github/workflows/static-analysis-php.yml@main + secrets: + COMPOSER_AUTH_JSON: ${{ secrets.PACKAGIST_AUTH_JSON }} + with: + PHP_VERSION: "8.0" + lint-php: + uses: inpsyde/reusable-workflows/.github/workflows/lint-php.yml@main + strategy: + matrix: + php: [ "8.0", "8.1", "8.2" ] + with: + PHP_VERSION: ${{ matrix.php }} + tests-unit-php: + needs: [ coding-standards-analysis-php, static-code-analysis-php ] + uses: inpsyde/reusable-workflows/.github/workflows/tests-unit-php.yml@main + strategy: + matrix: + php: [ "8.0", "8.1", "8.2" ] + with: + PHP_VERSION: ${{ matrix.php }} diff --git a/vendor/rrze/fau-studium-common/.gitignore b/vendor/rrze/fau-studium-common/.gitignore new file mode 100644 index 000000000..58e95924d --- /dev/null +++ b/vendor/rrze/fau-studium-common/.gitignore @@ -0,0 +1,3 @@ +composer.lock +/.phpunit.result.cache +/vendor diff --git a/vendor/rrze/fau-studium-common/LICENSE b/vendor/rrze/fau-studium-common/LICENSE new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/vendor/rrze/fau-studium-common/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/vendor/rrze/fau-studium-common/README.md b/vendor/rrze/fau-studium-common/README.md new file mode 100644 index 000000000..2649fd9e2 --- /dev/null +++ b/vendor/rrze/fau-studium-common/README.md @@ -0,0 +1,37 @@ +# FAU Degree Program Common + +Shared kernel for FAU Degree Program and FAU Degree Program Output plugins. + +## Table Of Contents + +* [Installation](#installation) +* [Design](#design) +* [Crafted by Syde](#crafted-by-syde) +* [License](#license) +* [Contributing](#contributing) + +## Installation + +The best way to use this package is: + +```BASH +$ composer require inpsyde/fau-degree-program-common +``` + +## Design + +The taxonomies of the degree program post type are mapped to Degree program entity properties. + +## Crafted by Syde + +The team at [Syde](https://syde.com) is engineering the Web since 2006. + +## License + +Copyright (c) 2022, Syde GmbH + +This software is released under the ["GNU General Public License v2.0 or later"](LICENSE) license. + +## Contributing + +All feedback / bug reports / pull requests are welcome. diff --git a/vendor/rrze/fau-studium-common/composer.json b/vendor/rrze/fau-studium-common/composer.json new file mode 100644 index 000000000..40151fb4b --- /dev/null +++ b/vendor/rrze/fau-studium-common/composer.json @@ -0,0 +1,74 @@ +{ + "name": "rrze/fau-studium-common", + "description": "Shared kernel for FAU Degree Program and FAU Degree Program Output plugins.", + "license": "GPL-2.0-or-later", + "type": "library", + "authors": [ + { + "name": "Syde GmbH", + "email": "hello@syde.com", + "homepage": "https://syde.com/", + "role": "Company" + } + ], + "require": { + "php": "^8.0", + "psr/event-dispatcher": "^1.0", + "psr/log": "^3.0", + "psr/simple-cache": "^3.0", + "webmozart/assert": "^1.11" + }, + "require-dev": { + "brain/monkey": "^2.6", + "inpsyde/php-coding-standards": "^1", + "inpsyde/wp-stubs-versions": "dev-latest", + "johnpbloch/wordpress-core": "^6.1", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.4", + "wp-cli/wp-cli": "^2.7" + }, + "suggest": { + "inpsyde/modularity": "Modular PSR-11 implementation for WordPress Plugins, Themes or Libraries" + }, + "repositories": [ + { + "type": "composer", + "url": "https://raw.githubusercontent.com/inpsyde/wp-stubs/main", + "only": [ + "inpsyde/wp-stubs-versions" + ] + } + ], + "minimum-stability": "dev", + "prefer-stable": true, + "autoload": { + "psr-4": { + "Fau\\DegreeProgram\\Common\\": "src/", + "Fau\\DegreeProgram\\Common\\LanguageExtension\\": "lib/lang-extension/src/" + } + }, + "autoload-dev": { + "psr-4": { + "Fau\\DegreeProgram\\Common\\Tests\\": [ + "tests/src/", + "tests/unit/", + "tests/functional/" + ], + "Fau\\DegreeProgram\\Common\\LanguageExtension\\Tests\\": "lib/lang-extension/tests/" + } + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + }, + "optimize-autoloader": true, + "sort-packages": true + }, + "scripts": { + "check-coding-standards": "vendor/bin/phpcs", + "check-psalm": "vendor/bin/psalm --no-cache", + "fix-coding-standards": "vendor/bin/phpcbf", + "tests": "@php ./vendor/phpunit/phpunit/phpunit --coverage-text", + "tests:no-cov": "@php ./vendor/phpunit/phpunit/phpunit --no-coverage" + } +} diff --git a/vendor/rrze/fau-studium-common/config/schema_draft.php b/vendor/rrze/fau-studium-common/config/schema_draft.php new file mode 100644 index 000000000..144bdf5de --- /dev/null +++ b/vendor/rrze/fau-studium-common/config/schema_draft.php @@ -0,0 +1,156 @@ + 'object', + 'additionalProperties' => false, + 'required' => JsonSchemaDegreeProgramDataValidator::REQUIRED_PROPERTIES, + 'properties' => [ + DegreeProgram::ID => [ + 'type' => 'integer', + 'minimum' => 1, + ], + DegreeProgram::SLUG => MultilingualString::SCHEMA, + DegreeProgram::FEATURED_IMAGE => Image::SCHEMA, + DegreeProgram::TEASER_IMAGE => Image::SCHEMA, + DegreeProgram::TITLE => MultilingualString::SCHEMA, + DegreeProgram::SUBTITLE => MultilingualString::SCHEMA, + DegreeProgram::STANDARD_DURATION => [ + 'type' => 'string', + ], + DegreeProgram::FEE_REQUIRED => [ + 'type' => 'boolean', + ], + DegreeProgram::START => MultilingualList::SCHEMA, + DegreeProgram::NUMBER_OF_STUDENTS => NumberOfStudents::SCHEMA, + DegreeProgram::TEACHING_LANGUAGE => MultilingualString::SCHEMA, + DegreeProgram::ATTRIBUTES => MultilingualList::SCHEMA, + DegreeProgram::DEGREE => Degree::SCHEMA, + DegreeProgram::FACULTY => MultilingualLinks::SCHEMA, + DegreeProgram::LOCATION => MultilingualList::SCHEMA, + DegreeProgram::SUBJECT_GROUPS => MultilingualList::SCHEMA, + DegreeProgram::VIDEOS => [ + 'type' => 'array', + 'maxItems' => 3, + 'items' => [ + 'type' => 'string', + 'format' => 'uri', + ], + ], + DegreeProgram::META_DESCRIPTION => MultilingualString::SCHEMA, + DegreeProgram::CONTENT => [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => [ + Content::ABOUT, + Content::STRUCTURE, + Content::SPECIALIZATIONS, + Content::QUALITIES_AND_SKILLS, + Content::WHY_SHOULD_STUDY, + Content::CAREER_PROSPECTS, + Content::SPECIAL_FEATURES, + Content::TESTIMONIALS, + ], + 'properties' => [ + Content::ABOUT => ContentItem::SCHEMA, + Content::STRUCTURE => ContentItem::SCHEMA, + Content::SPECIALIZATIONS => ContentItem::SCHEMA, + Content::QUALITIES_AND_SKILLS => ContentItem::SCHEMA, + Content::WHY_SHOULD_STUDY => ContentItem::SCHEMA, + Content::CAREER_PROSPECTS => ContentItem::SCHEMA, + Content::SPECIAL_FEATURES => ContentItem::SCHEMA, + Content::TESTIMONIALS => ContentItem::SCHEMA, + ], + ], + DegreeProgram::ADMISSION_REQUIREMENTS => [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => [ + AdmissionRequirements::BACHELOR_OR_TEACHING_DEGREE, + AdmissionRequirements::TEACHING_DEGREE_HIGHER_SEMESTER, + AdmissionRequirements::MASTER, + ], + 'properties' => [ + AdmissionRequirements::BACHELOR_OR_TEACHING_DEGREE => [ + 'oneOf' => [ + AdmissionRequirement::SCHEMA, + AdmissionRequirement::SCHEMA_EMPTY, + ], + ], + AdmissionRequirements::TEACHING_DEGREE_HIGHER_SEMESTER => [ + 'oneOf' => [ + AdmissionRequirement::SCHEMA, + AdmissionRequirement::SCHEMA_EMPTY, + ], + ], + AdmissionRequirements::MASTER => [ + 'oneOf' => [ + AdmissionRequirement::SCHEMA, + AdmissionRequirement::SCHEMA_EMPTY, + ], + ], + ], + ], + DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS => MultilingualString::SCHEMA, + DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER => [ + 'type' => 'string', + ], + DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER => [ + 'type' => 'string', + ], + DegreeProgram::DETAILS_AND_NOTES => MultilingualString::SCHEMA, + DegreeProgram::LANGUAGE_SKILLS => MultilingualString::SCHEMA, + DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY => [ + 'type' => 'string', + ], + DegreeProgram::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS => MultilingualLink::SCHEMA, + DegreeProgram::START_OF_SEMESTER => MultilingualLink::SCHEMA, + DegreeProgram::SEMESTER_DATES => MultilingualLink::SCHEMA, + DegreeProgram::EXAMINATIONS_OFFICE => MultilingualLink::SCHEMA, + DegreeProgram::EXAMINATION_REGULATIONS => [ + 'type' => 'string', + 'format' => 'uri', + ], + DegreeProgram::MODULE_HANDBOOK => [ + 'type' => 'string', + 'format' => 'uri', + ], + DegreeProgram::URL => MultilingualString::SCHEMA, + DegreeProgram::DEPARTMENT => MultilingualString::SCHEMA, + DegreeProgram::STUDENT_ADVICE => MultilingualLink::SCHEMA, + DegreeProgram::SUBJECT_SPECIFIC_ADVICE => MultilingualLink::SCHEMA, + DegreeProgram::SERVICE_CENTERS => MultilingualLink::SCHEMA, + DegreeProgram::INFO_BROCHURE => [ + 'type' => 'string', + 'format' => 'uri', + ], + DegreeProgram::SEMESTER_FEE => MultilingualLink::SCHEMA, + DegreeProgram::DEGREE_PROGRAM_FEES => MultilingualString::SCHEMA, + DegreeProgram::ABROAD_OPPORTUNITIES => MultilingualLink::SCHEMA, + DegreeProgram::KEYWORDS => MultilingualList::SCHEMA, + DegreeProgram::AREA_OF_STUDY => MultilingualLinks::SCHEMA, + DegreeProgram::COMBINATIONS => JsonSchemaDegreeProgramDataValidator::ARRAY_OF_IDS, + DegreeProgram::LIMITED_COMBINATIONS => JsonSchemaDegreeProgramDataValidator::ARRAY_OF_IDS, + DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS => MultilingualLink::SCHEMA, + DegreeProgram::STUDENT_INITIATIVES => MultilingualLink::SCHEMA, + DegreeProgram::APPLY_NOW_LINK => MultilingualLink::SCHEMA, + DegreeProgram::ENTRY_TEXT => MultilingualString::SCHEMA, + DegreeProgram::CAMPO_KEYS => CampoKeys::SCHEMA, + ], +]; diff --git a/vendor/rrze/fau-studium-common/config/schema_publish.php b/vendor/rrze/fau-studium-common/config/schema_publish.php new file mode 100644 index 000000000..dba036fd9 --- /dev/null +++ b/vendor/rrze/fau-studium-common/config/schema_publish.php @@ -0,0 +1,161 @@ + 'object', + 'additionalProperties' => false, + 'required' => JsonSchemaDegreeProgramDataValidator::REQUIRED_PROPERTIES, + 'properties' => [ + DegreeProgram::ID => [ + 'type' => 'integer', + 'minimum' => 1, + ], + DegreeProgram::SLUG => MultilingualString::SCHEMA, + DegreeProgram::FEATURED_IMAGE => Image::SCHEMA_REQUIRED, + DegreeProgram::TEASER_IMAGE => Image::SCHEMA_REQUIRED, + DegreeProgram::TITLE => MultilingualString::SCHEMA_REQUIRED, + DegreeProgram::SUBTITLE => MultilingualString::SCHEMA, + DegreeProgram::STANDARD_DURATION => [ + 'type' => 'string', + 'minLength' => 1, + ], + DegreeProgram::FEE_REQUIRED => [ + 'type' => 'boolean', + ], + DegreeProgram::START => MultilingualList::SCHEMA_REQUIRED, + DegreeProgram::NUMBER_OF_STUDENTS => NumberOfStudents::SCHEMA_REQUIRED, + DegreeProgram::TEACHING_LANGUAGE => MultilingualString::SCHEMA_ID_REQUIRED, + DegreeProgram::ATTRIBUTES => MultilingualList::SCHEMA, + DegreeProgram::DEGREE => Degree::SCHEMA_REQUIRED, + DegreeProgram::FACULTY => MultilingualLinks::SCHEMA_REQUIRED, + DegreeProgram::LOCATION => MultilingualList::SCHEMA_REQUIRED, + DegreeProgram::SUBJECT_GROUPS => MultilingualList::SCHEMA_REQUIRED, + DegreeProgram::VIDEOS => [ + 'type' => 'array', + 'maxItems' => 3, + 'items' => [ + 'type' => 'string', + 'format' => 'uri', + ], + ], + DegreeProgram::META_DESCRIPTION => MultilingualString::SCHEMA_REQUIRED, + DegreeProgram::CONTENT => [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => [ + Content::ABOUT, + Content::STRUCTURE, + Content::SPECIALIZATIONS, + Content::QUALITIES_AND_SKILLS, + Content::WHY_SHOULD_STUDY, + Content::CAREER_PROSPECTS, + Content::SPECIAL_FEATURES, + Content::TESTIMONIALS, + ], + 'properties' => [ + Content::ABOUT => ContentItem::SCHEMA_REQUIRED, + Content::STRUCTURE => ContentItem::SCHEMA_REQUIRED, + Content::SPECIALIZATIONS => ContentItem::SCHEMA, + Content::QUALITIES_AND_SKILLS => ContentItem::SCHEMA, + Content::WHY_SHOULD_STUDY => ContentItem::SCHEMA, + Content::CAREER_PROSPECTS => ContentItem::SCHEMA, + Content::SPECIAL_FEATURES => ContentItem::SCHEMA, + Content::TESTIMONIALS => ContentItem::SCHEMA, + ], + ], + DegreeProgram::ADMISSION_REQUIREMENTS => [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => [ + AdmissionRequirements::BACHELOR_OR_TEACHING_DEGREE, + AdmissionRequirements::TEACHING_DEGREE_HIGHER_SEMESTER, + AdmissionRequirements::MASTER, + ], + 'properties' => [ + AdmissionRequirements::BACHELOR_OR_TEACHING_DEGREE => [ + 'oneOf' => [ + AdmissionRequirement::SCHEMA, + AdmissionRequirement::SCHEMA_EMPTY, + ], + ], + AdmissionRequirements::TEACHING_DEGREE_HIGHER_SEMESTER => [ + 'oneOf' => [ + AdmissionRequirement::SCHEMA, + AdmissionRequirement::SCHEMA_EMPTY, + ], + ], + AdmissionRequirements::MASTER => [ + 'oneOf' => [ + AdmissionRequirement::SCHEMA, + AdmissionRequirement::SCHEMA_EMPTY, + ], + ], + ], + ], + DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS => MultilingualString::SCHEMA, + DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER => [ + 'type' => 'string', + 'pattern' => JsonSchemaDegreeProgramDataValidator::DEADLINE_PATTERN, + ], + DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER => [ + 'type' => 'string', + 'pattern' => JsonSchemaDegreeProgramDataValidator::DEADLINE_PATTERN, + ], + DegreeProgram::DETAILS_AND_NOTES => MultilingualString::SCHEMA, + DegreeProgram::LANGUAGE_SKILLS => MultilingualString::SCHEMA, + DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY => [ + 'type' => 'string', + ], + DegreeProgram::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS => MultilingualLink::SCHEMA_REQUIRED, + DegreeProgram::START_OF_SEMESTER => MultilingualLink::SCHEMA, + DegreeProgram::SEMESTER_DATES => MultilingualLink::SCHEMA, + DegreeProgram::EXAMINATIONS_OFFICE => MultilingualLink::SCHEMA_REQUIRED, + DegreeProgram::EXAMINATION_REGULATIONS => [ + 'type' => 'string', + 'minLength' => 1, + 'format' => 'uri', + ], + DegreeProgram::MODULE_HANDBOOK => [ + 'type' => 'string', + 'minLength' => 1, + 'format' => 'uri', + ], + DegreeProgram::URL => MultilingualString::SCHEMA_URL_REQUIRED, + DegreeProgram::DEPARTMENT => MultilingualString::SCHEMA_URL_REQUIRED, + DegreeProgram::STUDENT_ADVICE => MultilingualLink::SCHEMA, + DegreeProgram::SUBJECT_SPECIFIC_ADVICE => MultilingualLink::SCHEMA_REQUIRED, + DegreeProgram::SERVICE_CENTERS => MultilingualLink::SCHEMA, + DegreeProgram::INFO_BROCHURE => [ + 'type' => 'string', + 'format' => 'uri', + ], + DegreeProgram::SEMESTER_FEE => MultilingualLink::SCHEMA, + DegreeProgram::DEGREE_PROGRAM_FEES => MultilingualString::SCHEMA, + DegreeProgram::ABROAD_OPPORTUNITIES => MultilingualLink::SCHEMA, + DegreeProgram::KEYWORDS => MultilingualList::SCHEMA_REQUIRED, + DegreeProgram::AREA_OF_STUDY => MultilingualLinks::SCHEMA_REQUIRED, + DegreeProgram::COMBINATIONS => JsonSchemaDegreeProgramDataValidator::ARRAY_OF_IDS, + DegreeProgram::LIMITED_COMBINATIONS => JsonSchemaDegreeProgramDataValidator::ARRAY_OF_IDS, + DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS => MultilingualLink::SCHEMA, + DegreeProgram::STUDENT_INITIATIVES => MultilingualLink::SCHEMA, + DegreeProgram::APPLY_NOW_LINK => MultilingualLink::SCHEMA_REQUIRED, + DegreeProgram::ENTRY_TEXT => MultilingualString::SCHEMA_REQUIRED, + DegreeProgram::CAMPO_KEYS => CampoKeys::SCHEMA_REQUIRED, + ], +]; diff --git a/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE.mo b/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE.mo new file mode 100644 index 000000000..3872a2bfe Binary files /dev/null and b/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE.mo differ diff --git a/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE.po b/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE.po new file mode 100644 index 000000000..37603fbde --- /dev/null +++ b/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE.po @@ -0,0 +1,694 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-04-18T11:51:52+00:00\n" +"PO-Revision-Date: 2024-05-29 14:49+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.3.2\n" +"X-Domain: fau-degree-program-common\n" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:21 +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:66 +msgctxt "backoffice: post type label" +msgid "Degree Programs" +msgstr "Studiengänge" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:71 +msgctxt "backoffice: post type label" +msgid "Degree Program" +msgstr "Studiengang" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:76 +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:81 +msgctxt "backoffice: post type label" +msgid "Add New Degree Program" +msgstr "Neuen Studiengang erstellen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:86 +msgctxt "backoffice: post type label" +msgid "Edit Degree Program" +msgstr "Studiengang bearbeiten" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:91 +msgctxt "backoffice: post type label" +msgid "New Degree Program" +msgstr "Neuer Studiengang" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:96 +msgctxt "backoffice: post type label" +msgid "View Degree Program" +msgstr "Studiengang ansehen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:101 +msgctxt "backoffice: post type label" +msgid "View Degree Programs" +msgstr "Studiengänge ansehen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:106 +msgctxt "backoffice: post type label" +msgid "Search Degree Programs" +msgstr "Studiengänge durchsuchen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:111 +msgctxt "backoffice: post type label" +msgid "No degree programs found." +msgstr "Keine Studiengänge gefunden." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:116 +msgctxt "backoffice: post type label" +msgid "No degree programs found in Trash." +msgstr "Keine Studiengänge im Papierkorb gefunden." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:121 +msgctxt "backoffice: post type label" +msgid "All Degree Programs" +msgstr "Alle Studiengänge" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:126 +msgctxt "backoffice: post type label" +msgid "Degree Program Archives" +msgstr "Studiengangsarchive" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:131 +msgctxt "backoffice: post type label" +msgid "Degree Program Attributes" +msgstr "Studiengangsattribute" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:136 +msgctxt "backoffice: post type label" +msgid "Insert into degree program" +msgstr "In den Studiengang einfügen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:141 +msgctxt "backoffice: post type label" +msgid "Uploaded to this degree program" +msgstr "Zu diesem Studiengang hochgeladen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:146 +msgctxt "backoffice: post type label" +msgid "Filter degree programs list" +msgstr "Studiengangsliste filtern" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:151 +msgctxt "backoffice: post type label" +msgid "Degree programs list navigation" +msgstr "Navigation der Studiengangsliste" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:156 +msgctxt "backoffice: post type label" +msgid "Degree programs list" +msgstr "Studiengangsliste" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:161 +msgctxt "backoffice: post type label" +msgid "Degree program published." +msgstr "Studiengang veröffentlicht." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:166 +msgctxt "backoffice: post type label" +msgid "Degree program published privately." +msgstr "Studiengang privat veröffentlicht." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:171 +msgctxt "backoffice: post type label" +msgid "Degree program reverted to draft." +msgstr "Studiengang auf Entwurf zurückgesetzt." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:176 +msgctxt "backoffice: post type label" +msgid "Degree program scheduled." +msgstr "Studiengang geplant." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:181 +msgctxt "backoffice: post type label" +msgid "Degree program updated." +msgstr "Studiengang aktualisiert." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:186 +msgctxt "backoffice: navigation link block title" +msgid "Degree Program Link." +msgstr "Studiengangslink." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:191 +msgctxt "backoffice: navigation link block description" +msgid "A link to a degree program." +msgstr "Ein Link zu einem Studiengang." + +#: src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php:24 +msgctxt "backoffice: taxonomy plural name" +msgid "\"Apply now\" links" +msgstr "„Jetzt bewerben“-Links" + +#: src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php:33 +msgctxt "backoffice: taxonomy singular name" +msgid "\"Apply now\" link" +msgstr "„Jetzt bewerben“-Link" + +#: src/Infrastructure/Content/Taxonomy/AreaOfStudyTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Areas of study" +msgstr "Studienbereiche" + +#: src/Infrastructure/Content/Taxonomy/AreaOfStudyTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Area of study" +msgstr "Studienbereich" + +#: src/Infrastructure/Content/Taxonomy/AttributeTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Attributes" +msgstr "Attribute" + +#: src/Infrastructure/Content/Taxonomy/AttributeTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Attribute" +msgstr "Attribut" + +#: src/Infrastructure/Content/Taxonomy/DegreeTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Degrees" +msgstr "Abschlüsse" + +#: src/Infrastructure/Content/Taxonomy/DegreeTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Degree" +msgstr "Abschluss" + +#: src/Infrastructure/Content/Taxonomy/ExaminationsOfficeTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Examinations Offices" +msgstr "Prüfungsämter" + +#: src/Infrastructure/Content/Taxonomy/ExaminationsOfficeTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Examinations Office" +msgstr "Prüfungsamt" + +#: src/Infrastructure/Content/Taxonomy/FacultyTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Faculties" +msgstr "Fakultäten" + +#: src/Infrastructure/Content/Taxonomy/FacultyTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Faculty" +msgstr "Fakultät" + +#: src/Infrastructure/Content/Taxonomy/GermanLanguageSkillsForInternationalStudentsTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "German language skills for international students" +msgstr "Deutschkenntnisse für ausländische Studierende" + +#: src/Infrastructure/Content/Taxonomy/GermanLanguageSkillsForInternationalStudentsTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "German language skills for international students" +msgstr "Deutschkenntnisse für ausländische Studierende" + +#: src/Infrastructure/Content/Taxonomy/KeywordTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Keywords" +msgstr "Schlagwörter" + +#: src/Infrastructure/Content/Taxonomy/KeywordTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Keyword" +msgstr "Schlagwort" + +#: src/Infrastructure/Content/Taxonomy/MasterDegreeAdmissionRequirementTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Admission requirements Master’s degree" +msgstr "Zugangsvoraussetzungen Master" + +#: src/Infrastructure/Content/Taxonomy/MasterDegreeAdmissionRequirementTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Admission requirement Master’s degree" +msgstr "Zugangsvoraussetzung Master" + +#: src/Infrastructure/Content/Taxonomy/NumberOfStudentsTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Number of students" +msgstr "Studierendenzahl" + +#: src/Infrastructure/Content/Taxonomy/NumberOfStudentsTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Number of students" +msgstr "Studierendenzahl" + +#: src/Infrastructure/Content/Taxonomy/SemesterTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Semesters" +msgstr "Semester" + +#: src/Infrastructure/Content/Taxonomy/SemesterTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Semester" +msgstr "Semester" + +#: src/Infrastructure/Content/Taxonomy/StudyLocationTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Study locations" +msgstr "Studienorte" + +#: src/Infrastructure/Content/Taxonomy/StudyLocationTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Study location" +msgstr "Studienort" + +#: src/Infrastructure/Content/Taxonomy/SubjectGroupTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Subject groups" +msgstr "Fächergruppen" + +#: src/Infrastructure/Content/Taxonomy/SubjectGroupTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Subject group" +msgstr "Fächergruppe" + +#: src/Infrastructure/Content/Taxonomy/SubjectSpecificAdviceTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Subject-specific advices" +msgstr "Beratung aus dem Fach" + +#: src/Infrastructure/Content/Taxonomy/SubjectSpecificAdviceTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Subject-specific advice" +msgstr "Beratung aus dem Fach" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:77 +msgctxt "backoffice: taxonomy label" +msgid "Search %s" +msgstr "%s suchen" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:82 +msgctxt "backoffice: taxonomy label" +msgid "Popular %s" +msgstr "Beliebte %s" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:87 +msgctxt "backoffice: taxonomy label" +msgid "All %s" +msgstr "Alle %s" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:92 +msgctxt "backoffice: taxonomy label" +msgid "Parent %s" +msgstr "Übergeordnete %s" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:97 +msgctxt "backoffice: taxonomy label" +msgid "Parent %s:" +msgstr "Übergeordnete %s:" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:102 +msgctxt "backoffice: taxonomy label" +msgid "Edit %s" +msgstr "%s bearbeiten" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:107 +msgctxt "backoffice: taxonomy label" +msgid "View %s" +msgstr "%s ansehen" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:112 +msgctxt "backoffice: taxonomy label" +msgid "Update %s" +msgstr "%s aktualisieren" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:117 +msgctxt "backoffice: taxonomy label" +msgid "Add New %s" +msgstr "Neue/s %s hinzufügen" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:122 +msgctxt "backoffice: taxonomy label" +msgid "New %s Name" +msgstr "Neue/s &s-Name" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:127 +msgctxt "backoffice: taxonomy label" +msgid "Separate %s with commas" +msgstr "%s durch Kommas trennen" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:136 +msgctxt "backoffice: taxonomy label" +msgid "Add or remove %s" +msgstr "%s hinzufügen oder entfernen" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:141 +msgctxt "backoffice: taxonomy label" +msgid "Choose from the most used %s" +msgstr "Wähle aus den meistgenutzten %s" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:150 +msgctxt "backoffice: taxonomy label" +msgid "No %s found." +msgstr "Keine %s gefunden." + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:155 +msgctxt "backoffice: taxonomy label" +msgid "No %s" +msgstr "Keine %s" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:160 +msgctxt "backoffice: taxonomy label" +msgid "Filter by %s" +msgstr "Nach %s filtern" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:165 +msgctxt "backoffice: taxonomy label" +msgid "%s list navigation" +msgstr "Navigation der %s-Liste" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:174 +msgctxt "backoffice: taxonomy label" +msgid "%s list" +msgstr "%s-Liste" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:179 +msgctxt "backoffice: taxonomy label" +msgid "← Go to %s" +msgstr "← Weiter zu den %s" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:184 +msgctxt "backoffice: taxonomy label" +msgid "%s Link" +msgstr "%s-Link" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:189 +msgctxt "backoffice: taxonomy label" +msgid "A link to a %s." +msgstr "Ein Link zu eine/r %s." + +#: src/Infrastructure/Content/Taxonomy/TeachingLanguageTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Teaching languages" +msgstr "Unterrichtssprachen" + +#: src/Infrastructure/Content/Taxonomy/TeachingLanguageTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Teaching language" +msgstr "Unterrichtssprache" + +#: src/Infrastructure/Dashboard/AdminBar/AdminBarMenu.php:53 +msgctxt "backoffice: admin bar menu item" +msgid "FAU Degree Program" +msgstr "FAU Studiengang" + +#: src/Infrastructure/Content/Taxonomy/BachelorOrTeachingDegreeAdmissionRequirementTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Admission requirements Bachelor's/Teaching degrees" +msgstr "Zugangsvoraussetzungen Bachelor/Lehramt" + +#: src/Infrastructure/Content/Taxonomy/BachelorOrTeachingDegreeAdmissionRequirementTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Admission requirement Bachelor's/Teaching degrees" +msgstr "Zugangsvoraussetzung Bachelor/Lehramt" + +#: src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Admission requirements for entering a Bachelor's/teaching degree at a higher semester" +msgstr "Zugangsvoraussetzungen Bachelor/Lehramt höheres Semester" + +#: src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Admission requirement for entering a Bachelor's/teaching degree at a higher semester" +msgstr "Zugangsvoraussetzung Bachelor/Lehramt höheres Semester" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:173 +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:193 +msgctxt "rest_api: response status" +msgid "Degree program not found." +msgstr "Studiengang nicht gefunden." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:104 +msgctxt "rest_api: response status" +msgid "Something went wrong. Please try again later." +msgstr "Etwas ging schief. Bitte versuche es später noch einmal." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:124 +msgctxt "rest_api: response status" +msgid "The page number requested is larger than the number of pages available." +msgstr "Die angeforderte Seitenzahl ist größer als die Anzahl der verfügbaren Seiten." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:431 +msgctxt "rest_api: schema item description" +msgid "Admission requirement link." +msgstr "Zugangsvoraussetzungen-Link." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:439 +msgctxt "rest_api: schema item description" +msgid "Admission requirements." +msgstr "Zugangsvoraussetzungen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:463 +msgctxt "rest_api: schema item description" +msgid "Application deadline summer semester." +msgstr "Bewerbungsfrist Sommersemester." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:455 +msgctxt "rest_api: schema item description" +msgid "Application deadline winter semester." +msgstr "Bewerbungsfrist Wintersemester." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:367 +msgctxt "rest_api: schema item description" +msgid "Attributes." +msgstr "Attribute." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:632 +msgctxt "rest_api: schema item description" +msgid "Available translations." +msgstr "Verfügbare Übersetzungen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:447 +msgctxt "rest_api: schema item description" +msgid "Content-related admission requirements for Master’s degree." +msgstr "Inhaltliche Zugangsvoraussetzungen Master." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:423 +msgctxt "rest_api: schema item description" +msgid "Content." +msgstr "Inhalte." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:576 +msgctxt "rest_api: schema item description" +msgid "Counseling and Service Centers at FAU." +msgstr "Beratungs- und Servicestellen der FAU." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:528 +msgctxt "rest_api: schema item description" +msgid "Degree program and examination regulations." +msgstr "Studien- und Prüfungsordnungen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:600 +msgctxt "rest_api: schema item description" +msgid "Degree program fees." +msgstr "Studiengangsgebühren." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:624 +msgctxt "rest_api: schema item description" +msgid "Degree program limited possible combinations." +msgstr "Eingeschränkt mögliche Studiengangskombinationen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:616 +msgctxt "rest_api: schema item description" +msgid "Degree program possible combinations." +msgstr "Mögliche Studiengangskombinationen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:544 +msgctxt "rest_api: schema item description" +msgid "Degree program URL." +msgstr "Studiengang-URL." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:375 +msgctxt "rest_api: schema item description" +msgid "Degree." +msgstr "Abschluss." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:552 +msgctxt "rest_api: schema item description" +msgid "Department." +msgstr "Department." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:471 +msgctxt "rest_api: schema item description" +msgid "Details and notes." +msgstr "Details und Anmerkungen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:520 +msgctxt "rest_api: schema item description" +msgid "Examinations Office." +msgstr "Prüfungsamt." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:383 +msgctxt "rest_api: schema item description" +msgid "Faculty." +msgstr "Fakultät." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:295 +msgctxt "rest_api: schema item description" +msgid "Feature image." +msgstr "Beitragsbild." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:335 +msgctxt "rest_api: schema item description" +msgid "Fee required." +msgstr "Kostenpflichtig." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:584 +msgctxt "rest_api: schema item description" +msgid "Info brochure degree program." +msgstr "Infobroschüre Studiengang." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:496 +msgctxt "rest_api: schema item description" +msgid "Language certificates/German language skills for international applicants." +msgstr "Sprachnachweise/Deutschkenntnisse für internationale Bewerberinnen und Bewerber." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:487 +msgctxt "rest_api: schema item description" +msgid "Language skills for Faculty of Humanities, Social Sciences, and Theology only." +msgstr "Sprachkenntnisse nur für die Philosophische Fakultät und Fachbereich Theologie." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:479 +msgctxt "rest_api: schema item description" +msgid "Language skills." +msgstr "Sprachkenntnisse." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:415 +msgctxt "rest_api: schema item description" +msgid "Meta description." +msgstr "Metabeschreibung." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:536 +msgctxt "rest_api: schema item description" +msgid "Module handbook." +msgstr "Modulhandbuch." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:640 +msgctxt "rest_api: schema item description" +msgid "Notes for international applicants." +msgstr "Hinweise für internationale Bewerber." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:351 +msgctxt "rest_api: schema item description" +msgid "Number of students." +msgstr "Studierendenzahl." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:608 +msgctxt "rest_api: schema item description" +msgid "Opportunities for spending time abroad." +msgstr "Wege ins Ausland." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:512 +msgctxt "rest_api: schema item description" +msgid "Semester dates." +msgstr "Semestertermine." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:592 +msgctxt "rest_api: schema item description" +msgid "Semester fee." +msgstr "Semesterbeitrag." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:327 +msgctxt "rest_api: schema item description" +msgid "Standard duration of study." +msgstr "Regelstudienzeit." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:343 +msgctxt "rest_api: schema item description" +msgid "Start of degree program." +msgstr "Studienbeginn." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:504 +msgctxt "rest_api: schema item description" +msgid "Start of semester." +msgstr "Semesterstart." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:560 +msgctxt "rest_api: schema item description" +msgid "Student Advice and Career Service." +msgstr "Allgemeine Studienberatung." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:648 +msgctxt "rest_api: schema item description" +msgid "Students' Union/Student Initiatives." +msgstr "StuVe/FSI." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:391 +msgctxt "rest_api: schema item description" +msgid "Study location." +msgstr "Studienorte." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:399 +msgctxt "rest_api: schema item description" +msgid "Subject groups." +msgstr "Fächergruppen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:568 +msgctxt "rest_api: schema item description" +msgid "Subject-specific advice." +msgstr "Beratung aus dem Fach." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:319 +msgctxt "rest_api: schema item description" +msgid "Subtitle." +msgstr "Untertitel." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:359 +msgctxt "rest_api: schema item description" +msgid "Teaching language." +msgstr "Unterrichtssprache." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:303 +msgctxt "rest_api: schema item description" +msgid "Teaser image." +msgstr "Teaserbild." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:311 +msgctxt "rest_api: schema item description" +msgid "Title." +msgstr "Titel." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:287 +msgctxt "rest_api: schema item description" +msgid "Unique identifier for the degree program." +msgstr "Eindeutiger Bezeichner für den Studiengang." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:407 +msgctxt "rest_api: schema item description" +msgid "Videos." +msgstr "Videos." + +#: src/Infrastructure/Validator/ConditionalFieldsValidator.php:92 +msgctxt "backoffice: REST API error message" +msgid "This field can not be empty." +msgstr "Dieses Feld darf nicht leer sein." diff --git a/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE_formal.mo b/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE_formal.mo new file mode 100644 index 000000000..8eae06a18 Binary files /dev/null and b/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE_formal.mo differ diff --git a/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE_formal.po b/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE_formal.po new file mode 100644 index 000000000..b3a925790 --- /dev/null +++ b/vendor/rrze/fau-studium-common/languages/fau-degree-program-common-de_DE_formal.po @@ -0,0 +1,694 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-04-18T11:51:52+00:00\n" +"PO-Revision-Date: 2024-05-29 14:50+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.3.2\n" +"X-Domain: fau-degree-program-common\n" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:21 +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:66 +msgctxt "backoffice: post type label" +msgid "Degree Programs" +msgstr "Studiengänge" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:71 +msgctxt "backoffice: post type label" +msgid "Degree Program" +msgstr "Studiengang" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:76 +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:81 +msgctxt "backoffice: post type label" +msgid "Add New Degree Program" +msgstr "Neuen Studiengang erstellen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:86 +msgctxt "backoffice: post type label" +msgid "Edit Degree Program" +msgstr "Studiengang bearbeiten" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:91 +msgctxt "backoffice: post type label" +msgid "New Degree Program" +msgstr "Neuer Studiengang" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:96 +msgctxt "backoffice: post type label" +msgid "View Degree Program" +msgstr "Studiengang ansehen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:101 +msgctxt "backoffice: post type label" +msgid "View Degree Programs" +msgstr "Studiengänge ansehen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:106 +msgctxt "backoffice: post type label" +msgid "Search Degree Programs" +msgstr "Studiengänge durchsuchen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:111 +msgctxt "backoffice: post type label" +msgid "No degree programs found." +msgstr "Keine Studiengänge gefunden." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:116 +msgctxt "backoffice: post type label" +msgid "No degree programs found in Trash." +msgstr "Keine Studiengänge im Papierkorb gefunden." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:121 +msgctxt "backoffice: post type label" +msgid "All Degree Programs" +msgstr "Alle Studiengänge" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:126 +msgctxt "backoffice: post type label" +msgid "Degree Program Archives" +msgstr "Studiengangsarchive" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:131 +msgctxt "backoffice: post type label" +msgid "Degree Program Attributes" +msgstr "Studiengangsattribute" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:136 +msgctxt "backoffice: post type label" +msgid "Insert into degree program" +msgstr "In den Studiengang einfügen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:141 +msgctxt "backoffice: post type label" +msgid "Uploaded to this degree program" +msgstr "Zu diesem Studiengang hochgeladen" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:146 +msgctxt "backoffice: post type label" +msgid "Filter degree programs list" +msgstr "Studiengangsliste filtern" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:151 +msgctxt "backoffice: post type label" +msgid "Degree programs list navigation" +msgstr "Navigation der Studiengangsliste" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:156 +msgctxt "backoffice: post type label" +msgid "Degree programs list" +msgstr "Studiengangsliste" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:161 +msgctxt "backoffice: post type label" +msgid "Degree program published." +msgstr "Studiengang veröffentlicht." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:166 +msgctxt "backoffice: post type label" +msgid "Degree program published privately." +msgstr "Studiengang privat veröffentlicht." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:171 +msgctxt "backoffice: post type label" +msgid "Degree program reverted to draft." +msgstr "Studiengang auf Entwurf zurückgesetzt." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:176 +msgctxt "backoffice: post type label" +msgid "Degree program scheduled." +msgstr "Studiengang geplant." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:181 +msgctxt "backoffice: post type label" +msgid "Degree program updated." +msgstr "Studiengang aktualisiert." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:186 +msgctxt "backoffice: navigation link block title" +msgid "Degree Program Link." +msgstr "Studiengangslink." + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:191 +msgctxt "backoffice: navigation link block description" +msgid "A link to a degree program." +msgstr "Ein Link zu einem Studiengang." + +#: src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php:24 +msgctxt "backoffice: taxonomy plural name" +msgid "\"Apply now\" links" +msgstr "„Jetzt bewerben“-Links" + +#: src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php:33 +msgctxt "backoffice: taxonomy singular name" +msgid "\"Apply now\" link" +msgstr "„Jetzt bewerben“-Link" + +#: src/Infrastructure/Content/Taxonomy/AreaOfStudyTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Areas of study" +msgstr "Studienbereiche" + +#: src/Infrastructure/Content/Taxonomy/AreaOfStudyTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Area of study" +msgstr "Studienbereich" + +#: src/Infrastructure/Content/Taxonomy/AttributeTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Attributes" +msgstr "Attribute" + +#: src/Infrastructure/Content/Taxonomy/AttributeTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Attribute" +msgstr "Attribut" + +#: src/Infrastructure/Content/Taxonomy/DegreeTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Degrees" +msgstr "Abschlüsse" + +#: src/Infrastructure/Content/Taxonomy/DegreeTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Degree" +msgstr "Abschluss" + +#: src/Infrastructure/Content/Taxonomy/ExaminationsOfficeTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Examinations Offices" +msgstr "Prüfungsämter" + +#: src/Infrastructure/Content/Taxonomy/ExaminationsOfficeTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Examinations Office" +msgstr "Prüfungsamt" + +#: src/Infrastructure/Content/Taxonomy/FacultyTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Faculties" +msgstr "Fakultäten" + +#: src/Infrastructure/Content/Taxonomy/FacultyTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Faculty" +msgstr "Fakultät" + +#: src/Infrastructure/Content/Taxonomy/GermanLanguageSkillsForInternationalStudentsTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "German language skills for international students" +msgstr "Deutschkenntnisse für ausländische Studierende" + +#: src/Infrastructure/Content/Taxonomy/GermanLanguageSkillsForInternationalStudentsTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "German language skills for international students" +msgstr "Deutschkenntnisse für ausländische Studierende" + +#: src/Infrastructure/Content/Taxonomy/KeywordTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Keywords" +msgstr "Schlagwörter" + +#: src/Infrastructure/Content/Taxonomy/KeywordTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Keyword" +msgstr "Schlagwort" + +#: src/Infrastructure/Content/Taxonomy/MasterDegreeAdmissionRequirementTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Admission requirements Master’s degree" +msgstr "Zugangsvoraussetzungen Master" + +#: src/Infrastructure/Content/Taxonomy/MasterDegreeAdmissionRequirementTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Admission requirement Master’s degree" +msgstr "Zugangsvoraussetzung Master" + +#: src/Infrastructure/Content/Taxonomy/NumberOfStudentsTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Number of students" +msgstr "Studierendenzahl" + +#: src/Infrastructure/Content/Taxonomy/NumberOfStudentsTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Number of students" +msgstr "Studierendenzahl" + +#: src/Infrastructure/Content/Taxonomy/SemesterTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Semesters" +msgstr "Semester" + +#: src/Infrastructure/Content/Taxonomy/SemesterTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Semester" +msgstr "Semester" + +#: src/Infrastructure/Content/Taxonomy/StudyLocationTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Study locations" +msgstr "Studienorte" + +#: src/Infrastructure/Content/Taxonomy/StudyLocationTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Study location" +msgstr "Studienort" + +#: src/Infrastructure/Content/Taxonomy/SubjectGroupTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Subject groups" +msgstr "Fächergruppen" + +#: src/Infrastructure/Content/Taxonomy/SubjectGroupTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Subject group" +msgstr "Fächergruppe" + +#: src/Infrastructure/Content/Taxonomy/SubjectSpecificAdviceTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Subject-specific advices" +msgstr "Beratung aus dem Fach" + +#: src/Infrastructure/Content/Taxonomy/SubjectSpecificAdviceTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Subject-specific advice" +msgstr "Beratung aus dem Fach" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:77 +msgctxt "backoffice: taxonomy label" +msgid "Search %s" +msgstr "%s suchen" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:82 +msgctxt "backoffice: taxonomy label" +msgid "Popular %s" +msgstr "Beliebte %s" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:87 +msgctxt "backoffice: taxonomy label" +msgid "All %s" +msgstr "Alle %s" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:92 +msgctxt "backoffice: taxonomy label" +msgid "Parent %s" +msgstr "Übergeordnete %s" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:97 +msgctxt "backoffice: taxonomy label" +msgid "Parent %s:" +msgstr "Übergeordnete %s:" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:102 +msgctxt "backoffice: taxonomy label" +msgid "Edit %s" +msgstr "%s bearbeiten" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:107 +msgctxt "backoffice: taxonomy label" +msgid "View %s" +msgstr "%s ansehen" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:112 +msgctxt "backoffice: taxonomy label" +msgid "Update %s" +msgstr "%s aktualisieren" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:117 +msgctxt "backoffice: taxonomy label" +msgid "Add New %s" +msgstr "Neue/s %s hinzufügen" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:122 +msgctxt "backoffice: taxonomy label" +msgid "New %s Name" +msgstr "Neue/s &s-Name" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:127 +msgctxt "backoffice: taxonomy label" +msgid "Separate %s with commas" +msgstr "%s durch Kommas trennen" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:136 +msgctxt "backoffice: taxonomy label" +msgid "Add or remove %s" +msgstr "%s hinzufügen oder entfernen" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:141 +msgctxt "backoffice: taxonomy label" +msgid "Choose from the most used %s" +msgstr "Wählen Sie aus den meistgenutzten %s" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:150 +msgctxt "backoffice: taxonomy label" +msgid "No %s found." +msgstr "Keine %s gefunden." + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:155 +msgctxt "backoffice: taxonomy label" +msgid "No %s" +msgstr "Keine %s" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:160 +msgctxt "backoffice: taxonomy label" +msgid "Filter by %s" +msgstr "Nach %s filtern" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:165 +msgctxt "backoffice: taxonomy label" +msgid "%s list navigation" +msgstr "Navigation der %s-Liste" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:174 +msgctxt "backoffice: taxonomy label" +msgid "%s list" +msgstr "%s-Liste" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:179 +msgctxt "backoffice: taxonomy label" +msgid "← Go to %s" +msgstr "← Weiter zu den %s" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:184 +msgctxt "backoffice: taxonomy label" +msgid "%s Link" +msgstr "%s-Link" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:189 +msgctxt "backoffice: taxonomy label" +msgid "A link to a %s." +msgstr "Ein Link zu eine/r %s." + +#: src/Infrastructure/Content/Taxonomy/TeachingLanguageTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Teaching languages" +msgstr "Unterrichtssprachen" + +#: src/Infrastructure/Content/Taxonomy/TeachingLanguageTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Teaching language" +msgstr "Unterrichtssprache" + +#: src/Infrastructure/Dashboard/AdminBar/AdminBarMenu.php:53 +msgctxt "backoffice: admin bar menu item" +msgid "FAU Degree Program" +msgstr "FAU Studiengang" + +#: src/Infrastructure/Content/Taxonomy/BachelorOrTeachingDegreeAdmissionRequirementTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Admission requirements Bachelor's/Teaching degrees" +msgstr "Zugangsvoraussetzungen Bachelor/Lehramt" + +#: src/Infrastructure/Content/Taxonomy/BachelorOrTeachingDegreeAdmissionRequirementTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Admission requirement Bachelor's/Teaching degrees" +msgstr "Zugangsvoraussetzung Bachelor/Lehramt" + +#: src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Admission requirements for entering a Bachelor's/teaching degree at a higher semester" +msgstr "Zugangsvoraussetzungen Bachelor/Lehramt höheres Semester" + +#: src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Admission requirement for entering a Bachelor's/teaching degree at a higher semester" +msgstr "Zugangsvoraussetzung Bachelor/Lehramt höheres Semester" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:173 +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:193 +msgctxt "rest_api: response status" +msgid "Degree program not found." +msgstr "Studiengang nicht gefunden." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:104 +msgctxt "rest_api: response status" +msgid "Something went wrong. Please try again later." +msgstr "Etwas ging schief. Bitte versuchen Sie es später noch einmal." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:124 +msgctxt "rest_api: response status" +msgid "The page number requested is larger than the number of pages available." +msgstr "Die angeforderte Seitenzahl ist größer als die Anzahl der verfügbaren Seiten." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:431 +msgctxt "rest_api: schema item description" +msgid "Admission requirement link." +msgstr "Zugangsvoraussetzungen-Link." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:439 +msgctxt "rest_api: schema item description" +msgid "Admission requirements." +msgstr "Zugangsvoraussetzungen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:463 +msgctxt "rest_api: schema item description" +msgid "Application deadline summer semester." +msgstr "Bewerbungsfrist Sommersemester." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:455 +msgctxt "rest_api: schema item description" +msgid "Application deadline winter semester." +msgstr "Bewerbungsfrist Wintersemester." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:367 +msgctxt "rest_api: schema item description" +msgid "Attributes." +msgstr "Attribute." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:632 +msgctxt "rest_api: schema item description" +msgid "Available translations." +msgstr "Verfügbare Übersetzungen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:447 +msgctxt "rest_api: schema item description" +msgid "Content-related admission requirements for Master’s degree." +msgstr "Inhaltliche Zugangsvoraussetzungen Master." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:423 +msgctxt "rest_api: schema item description" +msgid "Content." +msgstr "Inhalte." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:576 +msgctxt "rest_api: schema item description" +msgid "Counseling and Service Centers at FAU." +msgstr "Beratungs- und Servicestellen der FAU." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:528 +msgctxt "rest_api: schema item description" +msgid "Degree program and examination regulations." +msgstr "Studien- und Prüfungsordnungen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:600 +msgctxt "rest_api: schema item description" +msgid "Degree program fees." +msgstr "Studiengangsgebühren." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:624 +msgctxt "rest_api: schema item description" +msgid "Degree program limited possible combinations." +msgstr "Eingeschränkt mögliche Studiengangskombinationen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:616 +msgctxt "rest_api: schema item description" +msgid "Degree program possible combinations." +msgstr "Mögliche Studiengangskombinationen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:544 +msgctxt "rest_api: schema item description" +msgid "Degree program URL." +msgstr "Studiengang-URL." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:375 +msgctxt "rest_api: schema item description" +msgid "Degree." +msgstr "Abschluss." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:552 +msgctxt "rest_api: schema item description" +msgid "Department." +msgstr "Department." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:471 +msgctxt "rest_api: schema item description" +msgid "Details and notes." +msgstr "Details und Anmerkungen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:520 +msgctxt "rest_api: schema item description" +msgid "Examinations Office." +msgstr "Prüfungsamt." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:383 +msgctxt "rest_api: schema item description" +msgid "Faculty." +msgstr "Fakultät." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:295 +msgctxt "rest_api: schema item description" +msgid "Feature image." +msgstr "Beitragsbild." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:335 +msgctxt "rest_api: schema item description" +msgid "Fee required." +msgstr "Kostenpflichtig." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:584 +msgctxt "rest_api: schema item description" +msgid "Info brochure degree program." +msgstr "Infobroschüre Studiengang." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:496 +msgctxt "rest_api: schema item description" +msgid "Language certificates/German language skills for international applicants." +msgstr "Sprachnachweise/Deutschkenntnisse für internationale Bewerberinnen und Bewerber." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:487 +msgctxt "rest_api: schema item description" +msgid "Language skills for Faculty of Humanities, Social Sciences, and Theology only." +msgstr "Sprachkenntnisse nur für die Philosophische Fakultät und Fachbereich Theologie." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:479 +msgctxt "rest_api: schema item description" +msgid "Language skills." +msgstr "Sprachkenntnisse." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:415 +msgctxt "rest_api: schema item description" +msgid "Meta description." +msgstr "Metabeschreibung." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:536 +msgctxt "rest_api: schema item description" +msgid "Module handbook." +msgstr "Modulhandbuch." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:640 +msgctxt "rest_api: schema item description" +msgid "Notes for international applicants." +msgstr "Hinweise für internationale Bewerber." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:351 +msgctxt "rest_api: schema item description" +msgid "Number of students." +msgstr "Studierendenzahl." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:608 +msgctxt "rest_api: schema item description" +msgid "Opportunities for spending time abroad." +msgstr "Wege ins Ausland." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:512 +msgctxt "rest_api: schema item description" +msgid "Semester dates." +msgstr "Semestertermine." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:592 +msgctxt "rest_api: schema item description" +msgid "Semester fee." +msgstr "Semesterbeitrag." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:327 +msgctxt "rest_api: schema item description" +msgid "Standard duration of study." +msgstr "Regelstudienzeit." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:343 +msgctxt "rest_api: schema item description" +msgid "Start of degree program." +msgstr "Studienbeginn." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:504 +msgctxt "rest_api: schema item description" +msgid "Start of semester." +msgstr "Semesterstart." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:560 +msgctxt "rest_api: schema item description" +msgid "Student Advice and Career Service." +msgstr "Allgemeine Studienberatung." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:648 +msgctxt "rest_api: schema item description" +msgid "Students' Union/Student Initiatives." +msgstr "StuVe/FSI." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:391 +msgctxt "rest_api: schema item description" +msgid "Study location." +msgstr "Studienorte." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:399 +msgctxt "rest_api: schema item description" +msgid "Subject groups." +msgstr "Fächergruppen." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:568 +msgctxt "rest_api: schema item description" +msgid "Subject-specific advice." +msgstr "Beratung aus dem Fach." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:319 +msgctxt "rest_api: schema item description" +msgid "Subtitle." +msgstr "Untertitel." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:359 +msgctxt "rest_api: schema item description" +msgid "Teaching language." +msgstr "Unterrichtssprache." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:303 +msgctxt "rest_api: schema item description" +msgid "Teaser image." +msgstr "Teaserbild." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:311 +msgctxt "rest_api: schema item description" +msgid "Title." +msgstr "Titel." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:287 +msgctxt "rest_api: schema item description" +msgid "Unique identifier for the degree program." +msgstr "Eindeutiger Bezeichner für den Studiengang." + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:407 +msgctxt "rest_api: schema item description" +msgid "Videos." +msgstr "Videos." + +#: src/Infrastructure/Validator/ConditionalFieldsValidator.php:92 +msgctxt "backoffice: REST API error message" +msgid "This field can not be empty." +msgstr "Dieses Feld darf nicht leer sein." diff --git a/vendor/rrze/fau-studium-common/languages/fau-degree-program-common.pot b/vendor/rrze/fau-studium-common/languages/fau-degree-program-common.pot new file mode 100644 index 000000000..e50806c29 --- /dev/null +++ b/vendor/rrze/fau-studium-common/languages/fau-degree-program-common.pot @@ -0,0 +1,702 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"POT-Creation-Date: 2024-05-29T12:47:59+00:00\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"X-Generator: WP-CLI 2.10.0\n" +"X-Domain: fau-degree-program-common\n" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:21 +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:66 +msgctxt "backoffice: post type label" +msgid "Degree Programs" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:71 +msgctxt "backoffice: post type label" +msgid "Degree Program" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:76 +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:81 +msgctxt "backoffice: post type label" +msgid "Add New Degree Program" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:86 +msgctxt "backoffice: post type label" +msgid "Edit Degree Program" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:91 +msgctxt "backoffice: post type label" +msgid "New Degree Program" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:96 +msgctxt "backoffice: post type label" +msgid "View Degree Program" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:101 +msgctxt "backoffice: post type label" +msgid "View Degree Programs" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:106 +msgctxt "backoffice: post type label" +msgid "Search Degree Programs" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:111 +msgctxt "backoffice: post type label" +msgid "No degree programs found." +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:116 +msgctxt "backoffice: post type label" +msgid "No degree programs found in Trash." +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:121 +msgctxt "backoffice: post type label" +msgid "All Degree Programs" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:126 +msgctxt "backoffice: post type label" +msgid "Degree Program Archives" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:131 +msgctxt "backoffice: post type label" +msgid "Degree Program Attributes" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:136 +msgctxt "backoffice: post type label" +msgid "Insert into degree program" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:141 +msgctxt "backoffice: post type label" +msgid "Uploaded to this degree program" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:146 +msgctxt "backoffice: post type label" +msgid "Filter degree programs list" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:151 +msgctxt "backoffice: post type label" +msgid "Degree programs list navigation" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:156 +msgctxt "backoffice: post type label" +msgid "Degree programs list" +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:161 +msgctxt "backoffice: post type label" +msgid "Degree program published." +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:166 +msgctxt "backoffice: post type label" +msgid "Degree program published privately." +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:171 +msgctxt "backoffice: post type label" +msgid "Degree program reverted to draft." +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:176 +msgctxt "backoffice: post type label" +msgid "Degree program scheduled." +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:181 +msgctxt "backoffice: post type label" +msgid "Degree program updated." +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:186 +msgctxt "backoffice: navigation link block title" +msgid "Degree Program Link." +msgstr "" + +#: src/Infrastructure/Content/PostType/DegreeProgramPostType.php:191 +msgctxt "backoffice: navigation link block description" +msgid "A link to a degree program." +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php:24 +msgctxt "backoffice: taxonomy plural name" +msgid "\"Apply now\" links" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php:33 +msgctxt "backoffice: taxonomy singular name" +msgid "\"Apply now\" link" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/AreaOfStudyTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Areas of study" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/AreaOfStudyTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Area of study" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/AttributeTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Attributes" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/AttributeTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Attribute" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/BachelorOrTeachingDegreeAdmissionRequirementTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Admission requirements Bachelor's/Teaching degrees" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/BachelorOrTeachingDegreeAdmissionRequirementTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Admission requirement Bachelor's/Teaching degrees" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/DegreeTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Degrees" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/DegreeTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Degree" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/ExaminationsOfficeTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Examinations Offices" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/ExaminationsOfficeTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Examinations Office" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/FacultyTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Faculties" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/FacultyTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Faculty" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/GermanLanguageSkillsForInternationalStudentsTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "German language skills for international students" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/GermanLanguageSkillsForInternationalStudentsTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "German language skills for international students" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/KeywordTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Keywords" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/KeywordTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Keyword" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/MasterDegreeAdmissionRequirementTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Admission requirements Master’s degree" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/MasterDegreeAdmissionRequirementTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Admission requirement Master’s degree" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/NumberOfStudentsTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Number of students" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/NumberOfStudentsTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Number of students" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/SemesterTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Semesters" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/SemesterTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Semester" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/StudyLocationTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Study locations" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/StudyLocationTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Study location" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/SubjectGroupTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Subject groups" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/SubjectGroupTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Subject group" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/SubjectSpecificAdviceTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Subject-specific advices" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/SubjectSpecificAdviceTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Subject-specific advice" +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:77 +msgctxt "backoffice: taxonomy label" +msgid "Search %s" +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:82 +msgctxt "backoffice: taxonomy label" +msgid "Popular %s" +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:87 +msgctxt "backoffice: taxonomy label" +msgid "All %s" +msgstr "" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:92 +msgctxt "backoffice: taxonomy label" +msgid "Parent %s" +msgstr "" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:97 +msgctxt "backoffice: taxonomy label" +msgid "Parent %s:" +msgstr "" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:102 +msgctxt "backoffice: taxonomy label" +msgid "Edit %s" +msgstr "" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:107 +msgctxt "backoffice: taxonomy label" +msgid "View %s" +msgstr "" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:112 +msgctxt "backoffice: taxonomy label" +msgid "Update %s" +msgstr "" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:117 +msgctxt "backoffice: taxonomy label" +msgid "Add New %s" +msgstr "" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:122 +msgctxt "backoffice: taxonomy label" +msgid "New %s Name" +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:127 +msgctxt "backoffice: taxonomy label" +msgid "Separate %s with commas" +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:136 +msgctxt "backoffice: taxonomy label" +msgid "Add or remove %s" +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:141 +msgctxt "backoffice: taxonomy label" +msgid "Choose from the most used %s" +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:150 +msgctxt "backoffice: taxonomy label" +msgid "No %s found." +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:155 +msgctxt "backoffice: taxonomy label" +msgid "No %s" +msgstr "" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:160 +msgctxt "backoffice: taxonomy label" +msgid "Filter by %s" +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:165 +msgctxt "backoffice: taxonomy label" +msgid "%s list navigation" +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:174 +msgctxt "backoffice: taxonomy label" +msgid "%s list" +msgstr "" + +#. translators: %s - taxonomy plural name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:179 +msgctxt "backoffice: taxonomy label" +msgid "← Go to %s" +msgstr "" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:184 +msgctxt "backoffice: taxonomy label" +msgid "%s Link" +msgstr "" + +#. translators: %s - taxonomy singular name +#: src/Infrastructure/Content/Taxonomy/Taxonomy.php:189 +msgctxt "backoffice: taxonomy label" +msgid "A link to a %s." +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php:27 +msgctxt "backoffice: taxonomy plural name" +msgid "Admission requirements for entering a Bachelor's/teaching degree at a higher semester" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php:36 +msgctxt "backoffice: taxonomy singular name" +msgid "Admission requirement for entering a Bachelor's/teaching degree at a higher semester" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/TeachingLanguageTaxonomy.php:29 +msgctxt "backoffice: taxonomy plural name" +msgid "Teaching languages" +msgstr "" + +#: src/Infrastructure/Content/Taxonomy/TeachingLanguageTaxonomy.php:38 +msgctxt "backoffice: taxonomy singular name" +msgid "Teaching language" +msgstr "" + +#: src/Infrastructure/Dashboard/AdminBar/AdminBarMenu.php:53 +msgctxt "backoffice: admin bar menu item" +msgid "FAU Degree Program" +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:128 +msgctxt "rest_api: response status" +msgid "Something went wrong. Please try again later." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:148 +msgctxt "rest_api: response status" +msgid "The page number requested is larger than the number of pages available." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:197 +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:217 +msgctxt "rest_api: response status" +msgid "Degree program not found." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:290 +msgctxt "rest_api: schema item description" +msgid "Language code (\"de\" and \"en\" are supported)." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:311 +msgctxt "rest_api: schema item description" +msgid "Unique identifier for the degree program." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:319 +msgctxt "rest_api: schema item description" +msgid "Feature image." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:327 +msgctxt "rest_api: schema item description" +msgid "Teaser image." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:335 +msgctxt "rest_api: schema item description" +msgid "Title." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:343 +msgctxt "rest_api: schema item description" +msgid "Subtitle." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:351 +msgctxt "rest_api: schema item description" +msgid "Standard duration of study." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:359 +msgctxt "rest_api: schema item description" +msgid "Fee required." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:367 +msgctxt "rest_api: schema item description" +msgid "Start of degree program." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:375 +msgctxt "rest_api: schema item description" +msgid "Number of students." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:383 +msgctxt "rest_api: schema item description" +msgid "Teaching language." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:391 +msgctxt "rest_api: schema item description" +msgid "Attributes." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:399 +msgctxt "rest_api: schema item description" +msgid "Degree." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:407 +msgctxt "rest_api: schema item description" +msgid "Faculty." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:415 +msgctxt "rest_api: schema item description" +msgid "Study location." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:423 +msgctxt "rest_api: schema item description" +msgid "Subject groups." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:431 +msgctxt "rest_api: schema item description" +msgid "Videos." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:439 +msgctxt "rest_api: schema item description" +msgid "Meta description." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:447 +msgctxt "rest_api: schema item description" +msgid "Content." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:455 +msgctxt "rest_api: schema item description" +msgid "Admission requirement link." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:463 +msgctxt "rest_api: schema item description" +msgid "Admission requirements." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:471 +msgctxt "rest_api: schema item description" +msgid "Content-related admission requirements for Master’s degree." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:479 +msgctxt "rest_api: schema item description" +msgid "Application deadline winter semester." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:487 +msgctxt "rest_api: schema item description" +msgid "Application deadline summer semester." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:495 +msgctxt "rest_api: schema item description" +msgid "Details and notes." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:503 +msgctxt "rest_api: schema item description" +msgid "Language skills." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:511 +msgctxt "rest_api: schema item description" +msgid "Language skills for Faculty of Humanities, Social Sciences, and Theology only." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:520 +msgctxt "rest_api: schema item description" +msgid "Language certificates/German language skills for international applicants." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:528 +msgctxt "rest_api: schema item description" +msgid "Start of semester." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:536 +msgctxt "rest_api: schema item description" +msgid "Semester dates." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:544 +msgctxt "rest_api: schema item description" +msgid "Examinations Office." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:552 +msgctxt "rest_api: schema item description" +msgid "Degree program and examination regulations." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:560 +msgctxt "rest_api: schema item description" +msgid "Module handbook." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:568 +msgctxt "rest_api: schema item description" +msgid "Degree program URL." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:576 +msgctxt "rest_api: schema item description" +msgid "Department." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:584 +msgctxt "rest_api: schema item description" +msgid "Student Advice and Career Service." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:592 +msgctxt "rest_api: schema item description" +msgid "Subject-specific advice." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:600 +msgctxt "rest_api: schema item description" +msgid "Counseling and Service Centers at FAU." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:608 +msgctxt "rest_api: schema item description" +msgid "Info brochure degree program." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:616 +msgctxt "rest_api: schema item description" +msgid "Semester fee." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:624 +msgctxt "rest_api: schema item description" +msgid "Degree program fees." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:632 +msgctxt "rest_api: schema item description" +msgid "Opportunities for spending time abroad." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:640 +msgctxt "rest_api: schema item description" +msgid "Degree program possible combinations." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:648 +msgctxt "rest_api: schema item description" +msgid "Degree program limited possible combinations." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:656 +msgctxt "rest_api: schema item description" +msgid "Available translations." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:664 +msgctxt "rest_api: schema item description" +msgid "Notes for international applicants." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:672 +msgctxt "rest_api: schema item description" +msgid "Students' Union/Student Initiatives." +msgstr "" + +#: src/Infrastructure/RestApi/TranslatedDegreeProgramController.php:680 +msgctxt "rest_api: schema item description" +msgid "Degree program Campo Keys." +msgstr "" + +#: src/Infrastructure/Validator/ConditionalFieldsValidator.php:92 +msgctxt "backoffice: REST API error message" +msgid "This field can not be empty." +msgstr "" diff --git a/vendor/rrze/fau-studium-common/lib/lang-extension/src/ArrayChangeset.php b/vendor/rrze/fau-studium-common/lib/lang-extension/src/ArrayChangeset.php new file mode 100644 index 000000000..307dc887d --- /dev/null +++ b/vendor/rrze/fau-studium-common/lib/lang-extension/src/ArrayChangeset.php @@ -0,0 +1,60 @@ + $old + * @param array $new + */ + private function __construct( + private array $old, + private array $new, + ){} + + /** + * @template T + * @param array $data + */ + public static function new( + array $data, + ): static { + return new static( + $data, + $data, + ); + } + + /** + * @param array $new + */ + public function applyChanges(array $new): static + { + return new static( + $this->old, + $new + ); + } + + /** + * @return array + */ + public function added(): array + { + return array_diff($this->new, $this->old); + } + + /** + * @return array + */ + public function removed(): array + { + return array_diff($this->old, $this->new); + } +} diff --git a/vendor/rrze/fau-studium-common/lib/lang-extension/src/ArrayOfStrings.php b/vendor/rrze/fau-studium-common/lib/lang-extension/src/ArrayOfStrings.php new file mode 100644 index 000000000..1f43a1a92 --- /dev/null +++ b/vendor/rrze/fau-studium-common/lib/lang-extension/src/ArrayOfStrings.php @@ -0,0 +1,23 @@ + + */ +final class ArrayOfStrings extends ArrayObject +{ + private function __construct(string ...$strings) + { + parent::__construct($strings); + } + + public static function new(string ...$strings): self + { + return new self(...$strings); + } +} diff --git a/vendor/rrze/fau-studium-common/lib/lang-extension/src/IntegersListChangeset.php b/vendor/rrze/fau-studium-common/lib/lang-extension/src/IntegersListChangeset.php new file mode 100644 index 000000000..ab2d60ce2 --- /dev/null +++ b/vendor/rrze/fau-studium-common/lib/lang-extension/src/IntegersListChangeset.php @@ -0,0 +1,27 @@ + + */ +final class IntegersListChangeset extends ArrayChangeset +{ + /** + * @return array + */ + public function added(): array + { + return array_values(parent::added()); + } + + /** + * @return array + */ + public function removed(): array + { + return array_values(parent::removed()); + } +} diff --git a/vendor/rrze/fau-studium-common/lib/lang-extension/tests/IntegersListChangesetTest.php b/vendor/rrze/fau-studium-common/lib/lang-extension/tests/IntegersListChangesetTest.php new file mode 100644 index 000000000..e3948e559 --- /dev/null +++ b/vendor/rrze/fau-studium-common/lib/lang-extension/tests/IntegersListChangesetTest.php @@ -0,0 +1,51 @@ +assertSame([], $changeset->added()); + $this->assertSame([], $changeset->removed()); + } + + public function testIntegers(): void + { + $changeset = IntegersListChangeset::new( + [1,2,3], + )->applyChanges([2,4,5]); + + $this->assertSame([4,5], $changeset->added()); + $this->assertSame([1,3], $changeset->removed()); + } + + public function testUnchanged(): void + { + $changeset = IntegersListChangeset::new( + [1,2,3], + )->applyChanges([1,2,3]); + + $this->assertSame([], $changeset->added()); + $this->assertSame([], $changeset->removed()); + } + + public function testEmptiness(): void + { + $changeset = IntegersListChangeset::new( + [1,2,3], + )->applyChanges([]); + + $this->assertSame([], $changeset->added()); + $this->assertSame([1,2,3], $changeset->removed()); + } +} diff --git a/vendor/rrze/fau-studium-common/phpcs.xml.dist b/vendor/rrze/fau-studium-common/phpcs.xml.dist new file mode 100644 index 000000000..b851e8150 --- /dev/null +++ b/vendor/rrze/fau-studium-common/phpcs.xml.dist @@ -0,0 +1,48 @@ + + + ./src/ + ./tests/ + + + + + + + + + + + + + + + + + + + Repository.php + Cache.php + + + + Cache.php + + + + */templates/* + + + + ./tests/* + + + + ./tests/* + + + */vendor/* + diff --git a/vendor/rrze/fau-studium-common/phpunit.xml.dist b/vendor/rrze/fau-studium-common/phpunit.xml.dist new file mode 100644 index 000000000..7b1823524 --- /dev/null +++ b/vendor/rrze/fau-studium-common/phpunit.xml.dist @@ -0,0 +1,26 @@ + + + + + src + + + + + tests/unit + + + tests/functional + + + lib/lang-extension/tests + + + diff --git a/vendor/rrze/fau-studium-common/psalm-baseline.xml b/vendor/rrze/fau-studium-common/psalm-baseline.xml new file mode 100644 index 000000000..7f8c7f473 --- /dev/null +++ b/vendor/rrze/fau-studium-common/psalm-baseline.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + args()['search'])]]> + + + + + + + + diff --git a/vendor/rrze/fau-studium-common/psalm.xml b/vendor/rrze/fau-studium-common/psalm.xml new file mode 100644 index 000000000..6f594d887 --- /dev/null +++ b/vendor/rrze/fau-studium-common/psalm.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/rrze/fau-studium-common/src/Application/AdmissionRequirementTranslated.php b/vendor/rrze/fau-studium-common/src/Application/AdmissionRequirementTranslated.php new file mode 100644 index 000000000..dee351f1d --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/AdmissionRequirementTranslated.php @@ -0,0 +1,116 @@ +current(), $languageCode), + $admissionRequirement->parent() + ? self::fromAdmissionRequirement($admissionRequirement->parent(), $languageCode) + : null, + $admissionRequirement->slug() + ); + } + + /** + * @psalm-param AdmissionRequirementTranslatedType $data + */ + public static function fromArray(array $data): self + { + $currentData = [ + AdmissionRequirement::NAME => $data[AdmissionRequirement::NAME], + AdmissionRequirement::LINK_TEXT => $data[AdmissionRequirement::LINK_TEXT], + AdmissionRequirement::LINK_URL => $data[AdmissionRequirement::LINK_URL], + ]; + + /** @var AdmissionRequirementTranslatedType|null $parentData */ + $parentData = $data[AdmissionRequirement::PARENT]; + $slug = $data[AdmissionRequirement::SLUG] ?? ''; + + return new self( + Link::fromArray($currentData), + $parentData ? self::fromArray($parentData) : null, + $slug + ); + } + + /** + * @psalm-return AdmissionRequirementTranslatedType + */ + public function asArray(): array + { + /** @var AdmissionRequirementTranslated|null $parentData */ + $parentData = $this->parent?->asArray(); + $currentData = $this->current->asArray(); + $currentData[AdmissionRequirement::PARENT] = $parentData; + $currentData[AdmissionRequirement::SLUG] = $this->slug; + + return $currentData; + } + + public function name(): string + { + return $this->current->name(); + } + + public function slug(): string + { + return $this->slug; + } + + public function linkText(): string + { + return $this->current->linkText(); + } + + public function linkUrl(): string + { + return $this->current->linkUrl(); + } + + public function isEmpty(): bool + { + return !$this->linkUrl(); + } + + public function asHtml(): string + { + return $this->current->asHtml(); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/AdmissionRequirementsTranslated.php b/vendor/rrze/fau-studium-common/src/Application/AdmissionRequirementsTranslated.php new file mode 100644 index 000000000..ec95f0f02 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/AdmissionRequirementsTranslated.php @@ -0,0 +1,122 @@ + $requirements + */ + private function __construct( + private array $requirements + ) { + } + + /** + * @psalm-param array $admissionRequirements + */ + public static function new( + array $admissionRequirements, + ): self { + + return new self( + $admissionRequirements + ); + } + + public static function fromAdmissionRequirements( + AdmissionRequirements $admissionRequirements, + string $languageCode + ): self { + + $result = []; + if (!$admissionRequirements->master()->isEmpty()) { + $result[AdmissionRequirements::MASTER] = AdmissionRequirementTranslated::fromAdmissionRequirement( + $admissionRequirements->master(), + $languageCode, + ); + } + if (!$admissionRequirements->bachelorOrTeachingDegree()->isEmpty()) { + $result[AdmissionRequirements::BACHELOR_OR_TEACHING_DEGREE] = AdmissionRequirementTranslated::fromAdmissionRequirement( + $admissionRequirements->bachelorOrTeachingDegree(), + $languageCode, + ); + } + if (!$admissionRequirements->teachingDegreeHigherSemester()->isEmpty()) { + $result[AdmissionRequirements::TEACHING_DEGREE_HIGHER_SEMESTER] = AdmissionRequirementTranslated::fromAdmissionRequirement( + $admissionRequirements->teachingDegreeHigherSemester(), + $languageCode, + ); + } + + return new self( + $result + ); + } + + /** + * @psalm-param AdmissionRequirementsTranslatedType $data + */ + public static function fromArray(array $data): self + { + return new self( + array_map([AdmissionRequirementTranslated::class, 'fromArray'], $data) + ); + } + + /** + * @return AdmissionRequirementsTranslatedType + */ + public function asArray(): array + { + return array_map( + static fn(AdmissionRequirementTranslated $item) => $item->asArray(), + $this->requirements + ); + } + + /** + * @psalm-return array + */ + public function requirements(): array + { + return $this->requirements; + } + + public function mainLink(): ?AdmissionRequirementTranslated + { + return $this->requirements[AdmissionRequirements::MASTER] + ?? $this->requirements[AdmissionRequirements::BACHELOR_OR_TEACHING_DEGREE] + ?? $this->requirements[AdmissionRequirements::TEACHING_DEGREE_HIGHER_SEMESTER] + ?? null; + } + + public function bachelorOrTeachingDegree(): ?AdmissionRequirementTranslated + { + return $this->requirements[AdmissionRequirements::BACHELOR_OR_TEACHING_DEGREE] ?? null; + } + + public function teachingDegreeHigherSemester(): ?AdmissionRequirementTranslated + { + return $this->requirements[AdmissionRequirements::TEACHING_DEGREE_HIGHER_SEMESTER] ?? null; + } + + public function master(): ?AdmissionRequirementTranslated + { + return $this->requirements[AdmissionRequirements::MASTER] ?? null; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Cache/CacheInvalidator.php b/vendor/rrze/fau-studium-common/src/Application/Cache/CacheInvalidator.php new file mode 100644 index 000000000..5528a982f --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Cache/CacheInvalidator.php @@ -0,0 +1,88 @@ +cache->clear(); + if (!$result) { + $this->logger->error('Failed degree program full cache invalidation.'); + return false; + } + + $this->logger->info('Successful degree program full cache invalidation.'); + $this->eventDispatcher->dispatch(CacheInvalidated::fully()); + return true; + } + + /** + * @psalm-param array $ids + * + * @throws InvalidArgumentException + */ + public function invalidatePartially(array $ids): bool + { + if (count($ids) === 0) { + $this->logger->debug( + 'Skipped degree program partial cache invalidation because no IDs were provided.' + ); + return true; + } + + $result = []; + + $keys = []; + foreach ($ids as $id) { + $keys[] = $this->cacheKeyGenerator->generateForDegreeProgram( + DegreeProgramId::fromInt($id) + ); + + $keys[] = $this->cacheKeyGenerator->generateForDegreeProgram( + DegreeProgramId::fromInt($id), + CacheKeyGenerator::TRANSLATED_TYPE + ); + } + $result[] = $this->cache->deleteMultiple($keys); + + $wasSuccessful = !in_array(false, $result, true); + + if (!$wasSuccessful) { + $this->logger->error( + sprintf( + 'Failed degree program partial cache invalidation for IDs: %s.', + implode(', ', $ids) + ) + ); + return false; + } + + $this->logger->info( + sprintf( + 'Successful degree program partial cache invalidation for IDs: %s.', + implode(', ', $ids) + ) + ); + $this->eventDispatcher->dispatch(CacheInvalidated::partially($ids)); + + return true; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Cache/CacheKeyGenerator.php b/vendor/rrze/fau-studium-common/src/Application/Cache/CacheKeyGenerator.php new file mode 100644 index 000000000..982448830 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Cache/CacheKeyGenerator.php @@ -0,0 +1,66 @@ +generate($type, (string) $degreeProgramId->asInt()); + } + + /** + * @psalm-return list{'raw' | 'translated', int} + */ + public function parseForDegreeProgram(string $key): array + { + $parts = explode('_', $key); + + if (!$this->isValidKeyParts($parts)) { + throw new class ( + "Cache {$key} is invalid." + ) extends Exception implements InvalidArgumentException { + }; + } + + /** @var 'raw' | 'translated' $type */ + $type = $parts[2]; + + return [$type, (int) $parts[3]]; + } + + private function generate(string ...$parts): string + { + array_unshift($parts, 'fau', 'cache'); + + return implode('_', $parts); + } + + private function isValidKeyParts(array $parts): bool + { + if (count($parts) !== 4) { + return false; + } + + if ($parts[0] !== 'fau' || $parts[1] !== 'cache') { + return false; + } + + if (!in_array($parts[2], [self::RAW_TYPE, self::TRANSLATED_TYPE], true)) { + return false; + } + + return (int) $parts[3] >= 0; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Cache/CacheWarmer.php b/vendor/rrze/fau-studium-common/src/Application/Cache/CacheWarmer.php new file mode 100644 index 000000000..4057442f6 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Cache/CacheWarmer.php @@ -0,0 +1,126 @@ +withPerPage(-1); + + $result = $this->warm($criteria); + + if (!$result) { + $this->logger->error('Failed degree program full cache warming.'); + return false; + } + + $this->logger->info('Successful degree program full cache warming.'); + $this->eventDispatcher->dispatch(CacheWarmed::fully()); + + return true; + } + + /** + * @psalm-param array $ids + * + * @throws InvalidArgumentException + */ + public function warmPartially(array $ids): bool + { + if (count($ids) === 0) { + $this->logger->debug( + 'Skipped degree program partial cache warming because no IDs were provided.' + ); + return true; + } + + $criteria = CollectionCriteria::new() + ->withPerPage(-1) + ->withInclude($ids); + + $result = $this->warm($criteria); + + if (!$result) { + $this->logger->error( + sprintf( + 'Failed degree program cache partial warming for IDs: %s.', + implode(', ', $ids) + ) + ); + return false; + } + + $this->logger->info( + sprintf( + 'Successful degree program partial cache warming for IDs: %s.', + implode(', ', $ids) + ) + ); + $this->eventDispatcher->dispatch(CacheWarmed::partially($ids)); + + return true; + } + + /** + * @throws InvalidArgumentException + */ + private function warm(CollectionCriteria $criteria): bool + { + $rawCollection = $this->collectionRepository->findRawCollection($criteria); + $translatedCollection = $this->collectionRepository->findTranslatedCollection( + $criteria, + MultilingualString::DE + ); + + if ( + !$rawCollection instanceof PaginationAwareCollection + || !$translatedCollection instanceof PaginationAwareCollection + ) { + return false; + } + + $values = []; + foreach ($rawCollection as $item) { + $key = $this->cacheKeyGenerator->generateForDegreeProgram($item->id()); + $values[$key] = $item->asArray(); + } + + foreach ($translatedCollection as $item) { + $key = $this->cacheKeyGenerator->generateForDegreeProgram( + DegreeProgramId::fromInt($item->id()), + CacheKeyGenerator::TRANSLATED_TYPE + ); + + $values[$key] = $item->asArray(); + } + + return $this->cache->setMultiple($values); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/ConditionalFieldsFilter.php b/vendor/rrze/fau-studium-common/src/Application/ConditionalFieldsFilter.php new file mode 100644 index 000000000..214dc6ede --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/ConditionalFieldsFilter.php @@ -0,0 +1,146 @@ +asArray(); + + if (!$raw->isFeeRequired()) { + $data[DegreeProgram::DEGREE_PROGRAM_FEES] = MultilingualString::empty()->asArray(); + } + + if (!$this->isCombinationsEnabled($facultySlugs, $raw->degree())) { + $data[DegreeProgram::COMBINATIONS] = []; + $data[DegreeProgram::LIMITED_COMBINATIONS] = []; + } + + $data[DegreeProgram::ADMISSION_REQUIREMENTS] = $this->filterAdmissionRequirements( + $raw->admissionRequirements(), + $raw->degree() + ); + + if (!self::isMasterContext($raw->degree())) { + $data[DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS] = MultilingualString::empty()->asArray(); + } + + if (!self::isLanguageSkillForFacultyOfHumanitiesOnlyEnabled($facultySlugs, $raw->degree())) { + $data[DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY] = ''; + } + + if (!$raw->start()->containGermanString(self::SEMESTER_WINTER)) { + $data[DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER] = ''; + } + + if (!$raw->start()->containGermanString(self::SEMESTER_SUMMER)) { + $data[DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER] = ''; + } + + return DegreeProgramViewRaw::fromArray($data); + } + + public static function isBachelorContext(Degree $degree): bool + { + return ( + $degree->hasGermanAbbreviation(self::DEGREE_ABBREVIATION_GERMAN_BACHELOR) + || self::isAdditionalDegree($degree) + ); + } + + public static function isAdditionalDegree(Degree $degree): bool + { + return $degree->name()->inGerman() === self::ADDITIONAL_DEGREE_NAME; + } + + public static function isTeachingDegreeContext(Degree $degree): bool + { + return $degree->hasGermanAbbreviation(self::DEGREE_ABBREVIATION_GERMAN_TEACHING_DEGREE); + } + + public static function isMasterContext(Degree $degree): bool + { + return $degree->hasGermanAbbreviation(self::DEGREE_ABBREVIATION_GERMAN_MASTERS); + } + + public static function isBachelorOrTeachingDegreeContext(Degree $degree): bool + { + return self::isBachelorContext($degree) || self::isTeachingDegreeContext($degree); + } + + /** + * @return AdmissionRequirementsType + */ + private function filterAdmissionRequirements( + AdmissionRequirements $admissionRequirements, + Degree $degree + ): array { + + $result = $admissionRequirements->asArray(); + $empty = AdmissionRequirement::empty()->asArray(); + + if (!self::isMasterContext($degree)) { + $result[AdmissionRequirements::MASTER] = $empty; + } + + if (!self::isBachelorOrTeachingDegreeContext($degree)) { + $result[AdmissionRequirements::BACHELOR_OR_TEACHING_DEGREE] = $empty; + $result[AdmissionRequirements::TEACHING_DEGREE_HIGHER_SEMESTER] = $empty; + return $result; + } + + if ( + $admissionRequirements + ->bachelorOrTeachingDegree() + ->hasGermanName(self::ADMISSION_REQUIREMENT_FREE) + ) { + $result[AdmissionRequirements::TEACHING_DEGREE_HIGHER_SEMESTER] = $empty; + } + + return $result; + } + + private function isCombinationsEnabled(ArrayOfStrings $facultySlugs, Degree $degree): bool + { + return array_intersect( + $facultySlugs->getArrayCopy(), + self::ALLOWED_FACULTY_SLUGS_FOR_COMBINATION + ) && self::isBachelorContext($degree); + } + + public static function isLanguageSkillForFacultyOfHumanitiesOnlyEnabled( + ArrayOfStrings $facultySlugs, + Degree $degree + ): bool { + + return in_array( + self::FACULTY_PHILOSOPHY, + $facultySlugs->getArrayCopy(), + true + ) && self::isBachelorOrTeachingDegreeContext($degree); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/ContentItemTranslated.php b/vendor/rrze/fau-studium-common/src/Application/ContentItemTranslated.php new file mode 100644 index 000000000..4b463a5e9 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/ContentItemTranslated.php @@ -0,0 +1,76 @@ +title()->asString($languageCode), + $contentItem->description()->asString($languageCode), + ); + } + + /** + * @psalm-param ContentItemTranslatedType $data + */ + public static function fromArray(array $data): self + { + return new self( + $data[ContentItem::TITLE], + $data[ContentItem::DESCRIPTION], + ); + } + + /** + * @return ContentItemTranslatedType + */ + public function asArray(): array + { + return [ + ContentItem::TITLE => $this->title, + ContentItem::DESCRIPTION => $this->description, + ]; + } + + public function title(): string + { + return $this->title; + } + + public function description(): string + { + return $this->description; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/ContentTranslated.php b/vendor/rrze/fau-studium-common/src/Application/ContentTranslated.php new file mode 100644 index 000000000..ad5f4f729 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/ContentTranslated.php @@ -0,0 +1,165 @@ +about(), $languageCode), + ContentItemTranslated::fromContentItem($content->structure(), $languageCode), + ContentItemTranslated::fromContentItem($content->specializations(), $languageCode), + ContentItemTranslated::fromContentItem($content->qualitiesAndSkills(), $languageCode), + ContentItemTranslated::fromContentItem($content->whyShouldStudy(), $languageCode), + ContentItemTranslated::fromContentItem($content->careerProspects(), $languageCode), + ContentItemTranslated::fromContentItem($content->specialFeatures(), $languageCode), + ContentItemTranslated::fromContentItem($content->testimonials(), $languageCode), + ); + } + + /** + * @psalm-param ContentTranslatedType $data + */ + public static function fromArray(array $data): self + { + return new self( + ContentItemTranslated::fromArray($data[Content::ABOUT]), + ContentItemTranslated::fromArray($data[Content::STRUCTURE]), + ContentItemTranslated::fromArray($data[Content::SPECIALIZATIONS]), + ContentItemTranslated::fromArray($data[Content::QUALITIES_AND_SKILLS]), + ContentItemTranslated::fromArray($data[Content::WHY_SHOULD_STUDY]), + ContentItemTranslated::fromArray($data[Content::CAREER_PROSPECTS]), + ContentItemTranslated::fromArray($data[Content::SPECIAL_FEATURES]), + ContentItemTranslated::fromArray($data[Content::TESTIMONIALS]), + ); + } + + /** + * @return ContentTranslatedType + */ + public function asArray(): array + { + return [ + Content::ABOUT => $this->about->asArray(), + Content::STRUCTURE => $this->structure->asArray(), + Content::SPECIALIZATIONS => $this->specializations->asArray(), + Content::QUALITIES_AND_SKILLS => $this->qualitiesAndSkills->asArray(), + Content::WHY_SHOULD_STUDY => $this->whyShouldStudy->asArray(), + Content::CAREER_PROSPECTS => $this->careerProspects->asArray(), + Content::SPECIAL_FEATURES => $this->specialFeatures->asArray(), + Content::TESTIMONIALS => $this->testimonials->asArray(), + ]; + } + + /** + * @psalm-param callable(string): string $callback + */ + public function mapDescriptions(callable $callback): self + { + $content = $this->asArray(); + $contentItems = []; + foreach ($content as $item) { + $contentItems[] = ContentItemTranslated::new( + $item[ContentItem::TITLE], + $callback( + $item[ContentItem::DESCRIPTION] + ) + ); + } + return new self(...$contentItems); + } + + public function about(): ContentItemTranslated + { + return $this->about; + } + + public function structure(): ContentItemTranslated + { + return $this->structure; + } + + public function specializations(): ContentItemTranslated + { + return $this->specializations; + } + + public function qualitiesAndSkills(): ContentItemTranslated + { + return $this->qualitiesAndSkills; + } + + public function whyShouldStudy(): ContentItemTranslated + { + return $this->whyShouldStudy; + } + + public function careerProspects(): ContentItemTranslated + { + return $this->careerProspects; + } + + public function specialFeatures(): ContentItemTranslated + { + return $this->specialFeatures; + } + + public function testimonials(): ContentItemTranslated + { + return $this->testimonials; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/DegreeProgramViewRaw.php b/vendor/rrze/fau-studium-common/src/Application/DegreeProgramViewRaw.php new file mode 100644 index 000000000..8c7fad916 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/DegreeProgramViewRaw.php @@ -0,0 +1,526 @@ +asArray(); + return new self( + $data[DegreeProgram::ID], + $data[DegreeProgram::SLUG], + $data[DegreeProgram::FEATURED_IMAGE], + $data[DegreeProgram::TEASER_IMAGE], + $data[DegreeProgram::TITLE], + $data[DegreeProgram::SUBTITLE], + $data[DegreeProgram::STANDARD_DURATION], + $data[DegreeProgram::FEE_REQUIRED], + $data[DegreeProgram::START], + $data[DegreeProgram::NUMBER_OF_STUDENTS], + $data[DegreeProgram::TEACHING_LANGUAGE], + $data[DegreeProgram::ATTRIBUTES], + $data[DegreeProgram::DEGREE], + $data[DegreeProgram::FACULTY], + $data[DegreeProgram::LOCATION], + $data[DegreeProgram::SUBJECT_GROUPS], + $data[DegreeProgram::VIDEOS], + $data[DegreeProgram::META_DESCRIPTION], + $data[DegreeProgram::CONTENT], + $data[DegreeProgram::ADMISSION_REQUIREMENTS], + $data[DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS], + $data[DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER], + $data[DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER], + $data[DegreeProgram::DETAILS_AND_NOTES], + $data[DegreeProgram::LANGUAGE_SKILLS], + $data[DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY], + $data[DegreeProgram::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS], + $data[DegreeProgram::START_OF_SEMESTER], + $data[DegreeProgram::SEMESTER_DATES], + $data[DegreeProgram::EXAMINATIONS_OFFICE], + $data[DegreeProgram::EXAMINATION_REGULATIONS], + $data[DegreeProgram::MODULE_HANDBOOK], + $data[DegreeProgram::URL], + $data[DegreeProgram::DEPARTMENT], + $data[DegreeProgram::STUDENT_ADVICE], + $data[DegreeProgram::SUBJECT_SPECIFIC_ADVICE], + $data[DegreeProgram::SERVICE_CENTERS], + $data[DegreeProgram::INFO_BROCHURE], + $data[DegreeProgram::SEMESTER_FEE], + $data[DegreeProgram::DEGREE_PROGRAM_FEES], + $data[DegreeProgram::ABROAD_OPPORTUNITIES], + $data[DegreeProgram::KEYWORDS], + $data[DegreeProgram::AREA_OF_STUDY], + $data[DegreeProgram::COMBINATIONS], + $data[DegreeProgram::LIMITED_COMBINATIONS], + $data[DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS], + $data[DegreeProgram::STUDENT_INITIATIVES], + $data[DegreeProgram::APPLY_NOW_LINK], + $data[DegreeProgram::ENTRY_TEXT], + $data[DegreeProgram::CAMPO_KEYS], + ); + } + + /** + * + * @psalm-param DegreeProgramViewRawArrayType $data + * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + public static function fromArray(array $data): self + { + return new self( + id: DegreeProgramId::fromInt($data[DegreeProgram::ID]), + slug: MultilingualString::fromArray($data[DegreeProgram::SLUG]), + featuredImage: Image::fromArray($data[DegreeProgram::FEATURED_IMAGE]), + teaserImage: Image::fromArray($data[DegreeProgram::TEASER_IMAGE]), + title: MultilingualString::fromArray($data[DegreeProgram::TITLE]), + subtitle: MultilingualString::fromArray($data[DegreeProgram::SUBTITLE]), + standardDuration: $data[DegreeProgram::STANDARD_DURATION], + feeRequired: $data[DegreeProgram::FEE_REQUIRED], + start: MultilingualList::fromArray($data[DegreeProgram::START]), + numberOfStudents: NumberOfStudents::fromArray($data[DegreeProgram::NUMBER_OF_STUDENTS]), + teachingLanguage: MultilingualString::fromArray($data[DegreeProgram::TEACHING_LANGUAGE]), + attributes: MultilingualList::fromArray($data[DegreeProgram::ATTRIBUTES]), + degree: Degree::fromArray($data[DegreeProgram::DEGREE]), + faculty: MultilingualLinks::fromArray($data[DegreeProgram::FACULTY]), + location: MultilingualList::fromArray($data[DegreeProgram::LOCATION]), + subjectGroups: MultilingualList::fromArray($data[DegreeProgram::SUBJECT_GROUPS]), + videos: ArrayOfStrings::new(...$data[DegreeProgram::VIDEOS]), + metaDescription: MultilingualString::fromArray($data[DegreeProgram::META_DESCRIPTION]), + content: Content::fromArray($data[DegreeProgram::CONTENT]), + admissionRequirements: AdmissionRequirements::fromArray($data[DegreeProgram::ADMISSION_REQUIREMENTS]), + contentRelatedMasterRequirements: MultilingualString::fromArray($data[DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS]), + applicationDeadlineWinterSemester: $data[DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER], + applicationDeadlineSummerSemester: $data[DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER], + detailsAndNotes: MultilingualString::fromArray($data[DegreeProgram::DETAILS_AND_NOTES]), + languageSkills: MultilingualString::fromArray($data[DegreeProgram::LANGUAGE_SKILLS]), + languageSkillsHumanitiesFaculty: $data[DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY], + germanLanguageSkillsForInternationalStudents: MultilingualLink::fromArray($data[DegreeProgram::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS]), + startOfSemester: MultilingualLink::fromArray($data[DegreeProgram::START_OF_SEMESTER]), + semesterDates: MultilingualLink::fromArray($data[DegreeProgram::SEMESTER_DATES]), + examinationsOffice: MultilingualLink::fromArray($data[DegreeProgram::EXAMINATIONS_OFFICE]), + examinationRegulations: $data[DegreeProgram::EXAMINATION_REGULATIONS], + moduleHandbook: $data[DegreeProgram::MODULE_HANDBOOK], + url: MultilingualString::fromArray($data[DegreeProgram::URL]), + department: MultilingualString::fromArray($data[DegreeProgram::DEPARTMENT]), + studentAdvice: MultilingualLink::fromArray($data[DegreeProgram::STUDENT_ADVICE]), + subjectSpecificAdvice: MultilingualLink::fromArray($data[DegreeProgram::SUBJECT_SPECIFIC_ADVICE]), + serviceCenters: MultilingualLink::fromArray($data[DegreeProgram::SERVICE_CENTERS]), + infoBrochure: $data[DegreeProgram::INFO_BROCHURE], + semesterFee: MultilingualLink::fromArray($data[DegreeProgram::SEMESTER_FEE]), + degreeProgramFees: MultilingualString::fromArray($data[DegreeProgram::DEGREE_PROGRAM_FEES]), + abroadOpportunities: MultilingualLink::fromArray($data[DegreeProgram::ABROAD_OPPORTUNITIES]), + keywords: MultilingualList::fromArray($data[DegreeProgram::KEYWORDS]), + areaOfStudy: MultilingualLinks::fromArray($data[DegreeProgram::AREA_OF_STUDY]), + combinations: DegreeProgramIds::fromArray($data[DegreeProgram::COMBINATIONS]), + limitedCombinations: DegreeProgramIds::fromArray($data[DegreeProgram::LIMITED_COMBINATIONS]), + notesForInternationalApplicants: MultilingualLink::fromArray( + $data[DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS] + ), + studentInitiatives: MultilingualLink::fromArray( + $data[DegreeProgram::STUDENT_INITIATIVES] + ), + applyNowLink: MultilingualLink::fromArray($data[DegreeProgram::APPLY_NOW_LINK]), + entryText: MultilingualString::fromArray($data[DegreeProgram::ENTRY_TEXT]), + campoKeys: CampoKeys::fromArray($data[DegreeProgram::CAMPO_KEYS] ?? []), + ); + } + + /** + * @psalm-return DegreeProgramViewRawArrayType + * + * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + public function asArray(): array + { + return [ + DegreeProgram::ID => $this->id->asInt(), + DegreeProgram::SLUG => $this->slug->asArray(), + DegreeProgram::FEATURED_IMAGE => $this->featuredImage->asArray(), + DegreeProgram::TEASER_IMAGE => $this->teaserImage->asArray(), + DegreeProgram::TITLE => $this->title->asArray(), + DegreeProgram::SUBTITLE => $this->subtitle->asArray(), + DegreeProgram::STANDARD_DURATION => $this->standardDuration, + DegreeProgram::FEE_REQUIRED => $this->feeRequired, + DegreeProgram::START => $this->start->asArray(), + DegreeProgram::NUMBER_OF_STUDENTS => $this->numberOfStudents->asArray(), + DegreeProgram::TEACHING_LANGUAGE => $this->teachingLanguage->asArray(), + DegreeProgram::ATTRIBUTES => $this->attributes->asArray(), + DegreeProgram::DEGREE => $this->degree->asArray(), + DegreeProgram::FACULTY => $this->faculty->asArray(), + DegreeProgram::LOCATION => $this->location->asArray(), + DegreeProgram::SUBJECT_GROUPS => $this->subjectGroups->asArray(), + DegreeProgram::VIDEOS => $this->videos->getArrayCopy(), + DegreeProgram::META_DESCRIPTION => $this->metaDescription->asArray(), + DegreeProgram::CONTENT => $this->content->asArray(), + DegreeProgram::ADMISSION_REQUIREMENTS => $this->admissionRequirements->asArray(), + DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS => + $this->contentRelatedMasterRequirements->asArray(), + DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER => $this->applicationDeadlineWinterSemester, + DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER => $this->applicationDeadlineSummerSemester, + DegreeProgram::DETAILS_AND_NOTES => $this->detailsAndNotes->asArray(), + DegreeProgram::LANGUAGE_SKILLS => $this->languageSkills->asArray(), + DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY => + $this->languageSkillsHumanitiesFaculty, + DegreeProgram::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS => + $this->germanLanguageSkillsForInternationalStudents->asArray(), + DegreeProgram::START_OF_SEMESTER => $this->startOfSemester->asArray(), + DegreeProgram::SEMESTER_DATES => $this->semesterDates->asArray(), + DegreeProgram::EXAMINATIONS_OFFICE => $this->examinationsOffice->asArray(), + DegreeProgram::EXAMINATION_REGULATIONS => $this->examinationRegulations, + DegreeProgram::MODULE_HANDBOOK => $this->moduleHandbook, + DegreeProgram::URL => $this->url->asArray(), + DegreeProgram::DEPARTMENT => $this->department->asArray(), + DegreeProgram::STUDENT_ADVICE => $this->studentAdvice->asArray(), + DegreeProgram::SUBJECT_SPECIFIC_ADVICE => $this->subjectSpecificAdvice->asArray(), + DegreeProgram::SERVICE_CENTERS => $this->serviceCenters->asArray(), + DegreeProgram::INFO_BROCHURE => $this->infoBrochure, + DegreeProgram::SEMESTER_FEE => $this->semesterFee->asArray(), + DegreeProgram::DEGREE_PROGRAM_FEES => $this->degreeProgramFees->asArray(), + DegreeProgram::ABROAD_OPPORTUNITIES => $this->abroadOpportunities->asArray(), + DegreeProgram::KEYWORDS => $this->keywords->asArray(), + DegreeProgram::AREA_OF_STUDY => $this->areaOfStudy->asArray(), + DegreeProgram::COMBINATIONS => $this->combinations->asArray(), + DegreeProgram::LIMITED_COMBINATIONS => $this->limitedCombinations->asArray(), + DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS => $this->notesForInternationalApplicants->asArray(), + DegreeProgram::STUDENT_INITIATIVES => $this->studentInitiatives->asArray(), + DegreeProgram::APPLY_NOW_LINK => $this->applyNowLink->asArray(), + DegreeProgram::ENTRY_TEXT => $this->entryText->asArray(), + DegreeProgram::CAMPO_KEYS => $this->campoKeys->asArray(), + ]; + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } + + public function id(): DegreeProgramId + { + return $this->id; + } + + public function slug(): MultilingualString + { + return $this->slug; + } + + public function featuredImage(): Image + { + return $this->featuredImage; + } + + public function teaserImage(): Image + { + return $this->teaserImage; + } + + public function title(): MultilingualString + { + return $this->title; + } + + public function subtitle(): MultilingualString + { + return $this->subtitle; + } + + public function standardDuration(): string + { + return $this->standardDuration; + } + + public function isFeeRequired(): bool + { + return $this->feeRequired; + } + + public function start(): MultilingualList + { + return $this->start; + } + + public function numberOfStudents(): NumberOfStudents + { + return $this->numberOfStudents; + } + + public function teachingLanguage(): MultilingualString + { + return $this->teachingLanguage; + } + + public function attributes(): MultilingualList + { + return $this->attributes; + } + + public function degree(): Degree + { + return $this->degree; + } + + public function faculty(): MultilingualLinks + { + return $this->faculty; + } + + public function location(): MultilingualList + { + return $this->location; + } + + public function subjectGroups(): MultilingualList + { + return $this->subjectGroups; + } + + public function videos(): ArrayOfStrings + { + return $this->videos; + } + + public function metaDescription(): MultilingualString + { + return $this->metaDescription; + } + + public function content(): Content + { + return $this->content; + } + + public function admissionRequirements(): AdmissionRequirements + { + return $this->admissionRequirements; + } + + public function contentRelatedMasterRequirements(): MultilingualString + { + return $this->contentRelatedMasterRequirements; + } + + public function applicationDeadlineWinterSemester(): string + { + return $this->applicationDeadlineWinterSemester; + } + + public function applicationDeadlineSummerSemester(): string + { + return $this->applicationDeadlineSummerSemester; + } + + public function detailsAndNotes(): MultilingualString + { + return $this->detailsAndNotes; + } + + public function languageSkills(): MultilingualString + { + return $this->languageSkills; + } + + public function languageSkillsHumanitiesFaculty(): string + { + return $this->languageSkillsHumanitiesFaculty; + } + + public function germanLanguageSkillsForInternationalStudents(): MultilingualLink + { + return $this->germanLanguageSkillsForInternationalStudents; + } + + public function startOfSemester(): MultilingualLink + { + return $this->startOfSemester; + } + + public function semesterDates(): MultilingualLink + { + return $this->semesterDates; + } + + public function examinationsOffice(): MultilingualLink + { + return $this->examinationsOffice; + } + + public function examinationRegulations(): string + { + return $this->examinationRegulations; + } + + public function moduleHandbook(): string + { + return $this->moduleHandbook; + } + + public function url(): MultilingualString + { + return $this->url; + } + + public function department(): MultilingualString + { + return $this->department; + } + + public function studentAdvice(): MultilingualLink + { + return $this->studentAdvice; + } + + public function subjectSpecificAdvice(): MultilingualLink + { + return $this->subjectSpecificAdvice; + } + + public function serviceCenters(): MultilingualLink + { + return $this->serviceCenters; + } + + public function infoBrochure(): string + { + return $this->infoBrochure; + } + + public function semesterFee(): MultilingualLink + { + return $this->semesterFee; + } + + public function degreeProgramFees(): MultilingualString + { + return $this->degreeProgramFees; + } + + public function abroadOpportunities(): MultilingualLink + { + return $this->abroadOpportunities; + } + + public function keywords(): MultilingualList + { + return $this->keywords; + } + + public function areaOfStudy(): MultilingualLinks + { + return $this->areaOfStudy; + } + + public function combinations(): DegreeProgramIds + { + return $this->combinations; + } + + public function limitedCombinations(): DegreeProgramIds + { + return $this->limitedCombinations; + } + + public function notesForInternationalApplicants(): MultilingualLink + { + return $this->notesForInternationalApplicants; + } + + public function studentInitiatives(): MultilingualLink + { + return $this->studentInitiatives; + } + + public function applyNowLink(): MultilingualLink + { + return $this->applyNowLink; + } + + public function entryText(): MultilingualString + { + return $this->entryText; + } + + public function campoKeys(): CampoKeys + { + return $this->campoKeys; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/DegreeProgramViewTranslated.php b/vendor/rrze/fau-studium-common/src/Application/DegreeProgramViewTranslated.php new file mode 100644 index 000000000..e1d50cd9e --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/DegreeProgramViewTranslated.php @@ -0,0 +1,684 @@ +, + * number_of_students: NumberOfStudentsType, + * teaching_language: string, + * attributes: array, + * degree: DegreeTranslatedType, + * faculty: array, + * location: array, + * subject_groups: array, + * videos: array, + * meta_description: string, + * content: ContentTranslatedType, + * admission_requirements: AdmissionRequirementsTranslatedType, + * admission_requirement_link: AdmissionRequirementTranslatedType|null, + * content_related_master_requirements: string, + * application_deadline_winter_semester: string, + * application_deadline_summer_semester: string, + * details_and_notes: string, + * language_skills: string, + * language_skills_humanities_faculty: string, + * german_language_skills_for_international_students: LinkType, + * start_of_semester: LinkType, + * semester_dates: LinkType, + * examinations_office: LinkType, + * examination_regulations: string, + * module_handbook: string, + * url: string, + * department: string, + * student_advice: LinkType, + * subject_specific_advice: LinkType, + * service_centers: LinkType, + * info_brochure: string, + * semester_fee: LinkType, + * degree_program_fees: string, + * abroad_opportunities: LinkType, + * keywords: array, + * area_of_study: array, + * combinations: array, + * limited_combinations: array, + * notes_for_international_applicants: LinkType, + * student_initiatives: LinkType, + * apply_now_link: LinkType, + * entry_text: string, + * campo_keys: CampoKeysMap + * } + * @psalm-type DegreeProgramViewTranslatedArrayType = DegreeProgramTranslation & array{ + * id: int, + * translations: array, + * } + */ +final class DegreeProgramViewTranslated implements JsonSerializable +{ + public const LINK = 'link'; + public const LANG = 'lang'; + public const ADMISSION_REQUIREMENT_LINK = 'admission_requirement_link'; + public const TRANSLATIONS = 'translations'; + + /** @var array */ + private array $translations = []; + + public function __construct( + private DegreeProgramId $id, + private string $link, + private string $slug, + /** + * @var LanguageCodes $lang + */ + private string $lang, + private ImageView $featuredImage, + private ImageView $teaserImage, + private string $title, + private string $subtitle, + private string $standardDuration, + private bool $feeRequired, + private ArrayOfStrings $start, + private NumberOfStudents $numberOfStudents, + private string $teachingLanguage, + private ArrayOfStrings $attributes, + private DegreeTranslated $degree, + private Links $faculty, + private ArrayOfStrings $location, + private ArrayOfStrings $subjectGroups, + private ArrayOfStrings $videos, + private string $metaDescription, + private ContentTranslated $content, + private AdmissionRequirementsTranslated $admissionRequirements, + private ?AdmissionRequirementTranslated $admissionRequirementLink, + private string $contentRelatedMasterRequirements, + private string $applicationDeadlineWinterSemester, + private string $applicationDeadlineSummerSemester, + private string $detailsAndNotes, + private string $languageSkills, + private string $languageSkillsHumanitiesFaculty, + private Link $germanLanguageSkillsForInternationalStudents, + private Link $startOfSemester, + private Link $semesterDates, + private Link $examinationsOffice, + private string $examinationRegulations, + private string $moduleHandbook, + private string $url, + private string $department, + private Link $studentAdvice, + private Link $subjectSpecificAdvice, + private Link $serviceCenters, + private string $infoBrochure, + private Link $semesterFee, + private string $degreeProgramFees, + private Link $abroadOpportunities, + private ArrayOfStrings $keywords, + private Links $areaOfStudy, + private RelatedDegreePrograms $combinations, + private RelatedDegreePrograms $limitedCombinations, + private Link $notesForInternationalApplicants, + private Link $studentInitiatives, + private Link $applyNowLink, + private string $entryText, + private CampoKeys $campoKeys, + ) { + } + + /** + * @psalm-param LanguageCodes $languageCode + * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + public static function empty(int $id, string $languageCode): self + { + return new self( + DegreeProgramId::fromInt($id), + link: '', + slug: '', + lang: $languageCode, + featuredImage: ImageView::empty(), + teaserImage: ImageView::empty(), + title: '', + subtitle: '', + standardDuration: '', + feeRequired: false, + start: ArrayOfStrings::new(), + numberOfStudents: NumberOfStudents::empty(), + teachingLanguage: '', + attributes: ArrayOfStrings::new(), + degree: DegreeTranslated::new('', '', null), + faculty: Links::new(), + location: ArrayOfStrings::new(), + subjectGroups: ArrayOfStrings::new(), + videos: ArrayOfStrings::new(), + metaDescription: '', + content: ContentTranslated::new( + ...array_fill(0, 8, ContentItemTranslated::new('', '')) + ), + admissionRequirements: AdmissionRequirementsTranslated::new([]), + admissionRequirementLink: AdmissionRequirementTranslated::new(Link::empty(), null), + contentRelatedMasterRequirements: '', + applicationDeadlineWinterSemester: '', + applicationDeadlineSummerSemester: '', + detailsAndNotes: '', + languageSkills: '', + languageSkillsHumanitiesFaculty: '', + germanLanguageSkillsForInternationalStudents: Link::empty(), + startOfSemester: Link::empty(), + semesterDates: Link::empty(), + examinationsOffice: Link::empty(), + examinationRegulations: '', + moduleHandbook: '', + url: '', + department: '', + studentAdvice: Link::empty(), + subjectSpecificAdvice: Link::empty(), + serviceCenters: Link::empty(), + infoBrochure: '', + semesterFee: Link::empty(), + degreeProgramFees: '', + abroadOpportunities: Link::empty(), + keywords: ArrayOfStrings::new(), + areaOfStudy: Links::new(), + combinations: RelatedDegreePrograms::new(), + limitedCombinations: RelatedDegreePrograms::new(), + notesForInternationalApplicants: Link::empty(), + studentInitiatives: Link::empty(), + applyNowLink: Link::empty(), + entryText: '', + campoKeys: CampoKeys::empty(), + ); + } + + /** + * @psalm-param DegreeProgramTranslation & array{ + * id: int | numeric-string, + * translations?: array, + * } $data + * + * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + public static function fromArray(array $data): self + { + $main = new self( + id: DegreeProgramId::fromInt((int) $data[DegreeProgram::ID]), + link: $data[self::LINK], + slug: $data[DegreeProgram::SLUG], + lang: $data[self::LANG], + featuredImage: ImageView::fromArray($data[DegreeProgram::FEATURED_IMAGE]), + teaserImage: ImageView::fromArray($data[DegreeProgram::TEASER_IMAGE]), + title: $data[DegreeProgram::TITLE], + subtitle: $data[DegreeProgram::SUBTITLE], + standardDuration: $data[DegreeProgram::STANDARD_DURATION], + feeRequired: $data[DegreeProgram::FEE_REQUIRED], + start: ArrayOfStrings::new(...$data[DegreeProgram::START]), + numberOfStudents: NumberOfStudents::fromArray($data[DegreeProgram::NUMBER_OF_STUDENTS]), + teachingLanguage: $data[DegreeProgram::TEACHING_LANGUAGE], + attributes: ArrayOfStrings::new(...$data[DegreeProgram::ATTRIBUTES]), + degree: DegreeTranslated::fromArray($data[DegreeProgram::DEGREE]), + faculty: Links::fromArray($data[DegreeProgram::FACULTY]), + location: ArrayOfStrings::new(...$data[DegreeProgram::LOCATION]), + subjectGroups: ArrayOfStrings::new(...$data[DegreeProgram::SUBJECT_GROUPS]), + videos: ArrayOfStrings::new(...$data[DegreeProgram::VIDEOS]), + metaDescription: $data[DegreeProgram::META_DESCRIPTION], + content: ContentTranslated::fromArray($data[DegreeProgram::CONTENT]), + admissionRequirements: AdmissionRequirementsTranslated::fromArray($data[DegreeProgram::ADMISSION_REQUIREMENTS]), + admissionRequirementLink: !empty($data[self::ADMISSION_REQUIREMENT_LINK]) + ? AdmissionRequirementTranslated::fromArray($data[self::ADMISSION_REQUIREMENT_LINK]) + : null, + contentRelatedMasterRequirements: $data[DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS], + applicationDeadlineWinterSemester: $data[DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER], + applicationDeadlineSummerSemester: $data[DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER], + detailsAndNotes: $data[DegreeProgram::DETAILS_AND_NOTES], + languageSkills: $data[DegreeProgram::LANGUAGE_SKILLS], + languageSkillsHumanitiesFaculty: $data[DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY], + germanLanguageSkillsForInternationalStudents: Link::fromArray($data[DegreeProgram::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS]), + startOfSemester: Link::fromArray($data[DegreeProgram::START_OF_SEMESTER]), + semesterDates: Link::fromArray($data[DegreeProgram::SEMESTER_DATES]), + examinationsOffice: Link::fromArray($data[DegreeProgram::EXAMINATIONS_OFFICE]), + examinationRegulations: $data[DegreeProgram::EXAMINATION_REGULATIONS], + moduleHandbook: $data[DegreeProgram::MODULE_HANDBOOK], + url: $data[DegreeProgram::URL], + department: $data[DegreeProgram::DEPARTMENT], + studentAdvice: Link::fromArray($data[DegreeProgram::STUDENT_ADVICE]), + subjectSpecificAdvice: Link::fromArray($data[DegreeProgram::SUBJECT_SPECIFIC_ADVICE]), + serviceCenters: Link::fromArray($data[DegreeProgram::SERVICE_CENTERS]), + infoBrochure: $data[DegreeProgram::INFO_BROCHURE], + semesterFee: Link::fromArray($data[DegreeProgram::SEMESTER_FEE]), + degreeProgramFees: $data[DegreeProgram::DEGREE_PROGRAM_FEES], + abroadOpportunities: Link::fromArray($data[DegreeProgram::ABROAD_OPPORTUNITIES]), + keywords: ArrayOfStrings::new(...$data[DegreeProgram::KEYWORDS]), + areaOfStudy: Links::fromArray($data[DegreeProgram::AREA_OF_STUDY]), + combinations: RelatedDegreePrograms::fromArray($data[DegreeProgram::COMBINATIONS]), + limitedCombinations: RelatedDegreePrograms::fromArray($data[DegreeProgram::LIMITED_COMBINATIONS]), + notesForInternationalApplicants: Link::fromArray($data[DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS]), + studentInitiatives: Link::fromArray($data[DegreeProgram::STUDENT_INITIATIVES]), + applyNowLink: Link::fromArray($data[DegreeProgram::APPLY_NOW_LINK]), + entryText: $data[DegreeProgram::ENTRY_TEXT], + campoKeys: CampoKeys::fromArray($data[DegreeProgram::CAMPO_KEYS] ?? []), + ); + + if (empty($data[self::TRANSLATIONS])) { + return $main; + } + + foreach ($data[self::TRANSLATIONS] as $translationData) { + $translationData[DegreeProgram::ID] = $data[DegreeProgram::ID]; + $main = $main->withTranslation(self::fromArray($translationData), $translationData[self::LANG]); + } + + return $main; + } + + /** + * @return DegreeProgramViewTranslatedArrayType + */ + public function asArray(): array + { + return [ + DegreeProgram::ID => $this->id->asInt(), + self::LINK => $this->link, + DegreeProgram::SLUG => $this->slug, + self::LANG => $this->lang, + DegreeProgram::FEATURED_IMAGE => $this->featuredImage->asArray(), + DegreeProgram::TEASER_IMAGE => $this->teaserImage->asArray(), + DegreeProgram::TITLE => $this->title, + DegreeProgram::SUBTITLE => $this->subtitle, + DegreeProgram::STANDARD_DURATION => $this->standardDuration, + DegreeProgram::FEE_REQUIRED => $this->feeRequired, + DegreeProgram::START => $this->start->getArrayCopy(), + DegreeProgram::NUMBER_OF_STUDENTS => $this->numberOfStudents->asArray(), + DegreeProgram::TEACHING_LANGUAGE => $this->teachingLanguage, + DegreeProgram::ATTRIBUTES => $this->attributes->getArrayCopy(), + DegreeProgram::DEGREE => $this->degree->asArray(), + DegreeProgram::FACULTY => $this->faculty->asArray(), + DegreeProgram::LOCATION => $this->location->getArrayCopy(), + DegreeProgram::SUBJECT_GROUPS => $this->subjectGroups->getArrayCopy(), + DegreeProgram::VIDEOS => $this->videos->getArrayCopy(), + DegreeProgram::META_DESCRIPTION => $this->metaDescription, + DegreeProgram::CONTENT => $this->content->asArray(), + DegreeProgram::ADMISSION_REQUIREMENTS => $this->admissionRequirements->asArray(), + self::ADMISSION_REQUIREMENT_LINK => $this->admissionRequirementLink()?->asArray(), + DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS => $this->contentRelatedMasterRequirements, + DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER => $this->applicationDeadlineWinterSemester, + DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER => $this->applicationDeadlineSummerSemester, + DegreeProgram::DETAILS_AND_NOTES => $this->detailsAndNotes, + DegreeProgram::LANGUAGE_SKILLS => $this->languageSkills, + DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY => $this->languageSkillsHumanitiesFaculty, + DegreeProgram::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS => + $this->germanLanguageSkillsForInternationalStudents->asArray(), + DegreeProgram::START_OF_SEMESTER => $this->startOfSemester->asArray(), + DegreeProgram::SEMESTER_DATES => $this->semesterDates->asArray(), + DegreeProgram::EXAMINATIONS_OFFICE => $this->examinationsOffice->asArray(), + DegreeProgram::EXAMINATION_REGULATIONS => $this->examinationRegulations, + DegreeProgram::MODULE_HANDBOOK => $this->moduleHandbook, + DegreeProgram::URL => $this->url, + DegreeProgram::DEPARTMENT => $this->department, + DegreeProgram::STUDENT_ADVICE => $this->studentAdvice->asArray(), + DegreeProgram::SUBJECT_SPECIFIC_ADVICE => $this->subjectSpecificAdvice->asArray(), + DegreeProgram::SERVICE_CENTERS => $this->serviceCenters->asArray(), + DegreeProgram::INFO_BROCHURE => $this->infoBrochure, + DegreeProgram::SEMESTER_FEE => $this->semesterFee->asArray(), + DegreeProgram::DEGREE_PROGRAM_FEES => $this->degreeProgramFees, + DegreeProgram::ABROAD_OPPORTUNITIES => $this->abroadOpportunities->asArray(), + DegreeProgram::KEYWORDS => $this->keywords->getArrayCopy(), + DegreeProgram::AREA_OF_STUDY => $this->areaOfStudy->asArray(), + DegreeProgram::COMBINATIONS => $this->combinations->asArray(), + DegreeProgram::LIMITED_COMBINATIONS => $this->limitedCombinations->asArray(), + DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS => $this->notesForInternationalApplicants->asArray(), + DegreeProgram::STUDENT_INITIATIVES => $this->studentInitiatives->asArray(), + DegreeProgram::APPLY_NOW_LINK => $this->applyNowLink->asArray(), + DegreeProgram::ENTRY_TEXT => $this->entryText, + DegreeProgram::CAMPO_KEYS => $this->campoKeys->asArray(), + self::TRANSLATIONS => $this->translationsAsArray(), + ]; + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } + + /** + * @psalm-param LanguageCodes $languageCode + */ + public function withTranslation( + DegreeProgramViewTranslated $degreeProgramViewTranslated, + string $languageCode, + ): self { + + $instance = clone $this; + $instance->translations[$languageCode] = $degreeProgramViewTranslated; + + return $instance; + } + + /** + * @psalm-param LanguageCodes $languageCode + */ + public function withBaseLang(string $languageCode): ?self + { + if ($languageCode === $this->lang) { + return $this; + } + + if (!isset($this->translations[$languageCode])) { + return null; + } + + $main = $this->translations[$languageCode]; + $translation = clone $this; + $translation->translations = []; + $main->withTranslation($translation, $languageCode); + + return $main; + } + + /** + * @return array + */ + private function translationsAsArray(): array + { + return array_map(static function (DegreeProgramViewTranslated $view): array { + $result = $view->asArray(); + unset($result[DegreeProgram::ID], $result[self::TRANSLATIONS]); + + return $result; + }, $this->translations); + } + + public function id(): int + { + return $this->id->asInt(); + } + + public function link(): string + { + return $this->link; + } + + public function slug(): string + { + return $this->slug; + } + + /** + * @return LanguageCodes + */ + public function lang(): string + { + return $this->lang; + } + + public function featuredImage(): ImageView + { + return $this->featuredImage; + } + + public function teaserImage(): ImageView + { + return $this->teaserImage; + } + + public function title(): string + { + return $this->title; + } + + public function subtitle(): string + { + return $this->subtitle; + } + + public function standardDuration(): string + { + return $this->standardDuration; + } + + public function isFeeRequired(): bool + { + return $this->feeRequired; + } + + public function start(): ArrayOfStrings + { + return $this->start; + } + + public function numberOfStudents(): NumberOfStudents + { + return $this->numberOfStudents; + } + + public function teachingLanguage(): string + { + return $this->teachingLanguage; + } + + public function attributes(): ArrayOfStrings + { + return $this->attributes; + } + + public function degree(): DegreeTranslated + { + return $this->degree; + } + + public function faculty(): Links + { + return $this->faculty; + } + + public function location(): ArrayOfStrings + { + return $this->location; + } + + public function subjectGroups(): ArrayOfStrings + { + return $this->subjectGroups; + } + + public function videos(): ArrayOfStrings + { + return $this->videos; + } + + public function metaDescription(): string + { + return $this->metaDescription; + } + + public function content(): ContentTranslated + { + return $this->content; + } + + public function admissionRequirements(): AdmissionRequirementsTranslated + { + return $this->admissionRequirements; + } + + public function admissionRequirementLink(): ?AdmissionRequirementTranslated + { + return $this->admissionRequirementLink; + } + + public function contentRelatedMasterRequirements(): string + { + return $this->contentRelatedMasterRequirements; + } + + public function applicationDeadlineWinterSemester(): string + { + return $this->applicationDeadlineWinterSemester; + } + + public function applicationDeadlineSummerSemester(): string + { + return $this->applicationDeadlineSummerSemester; + } + + public function detailsAndNotes(): string + { + return $this->detailsAndNotes; + } + + public function languageSkills(): string + { + return $this->languageSkills; + } + + public function languageSkillsHumanitiesFaculty(): string + { + return $this->languageSkillsHumanitiesFaculty; + } + + public function germanLanguageSkillsForInternationalStudents(): Link + { + return $this->germanLanguageSkillsForInternationalStudents; + } + + public function startOfSemester(): Link + { + return $this->startOfSemester; + } + + public function semesterDates(): Link + { + return $this->semesterDates; + } + + public function examinationsOffice(): Link + { + return $this->examinationsOffice; + } + + public function examinationRegulations(): string + { + return $this->examinationRegulations; + } + + public function moduleHandbook(): string + { + return $this->moduleHandbook; + } + + public function url(): string + { + return $this->url; + } + + public function department(): string + { + return $this->department; + } + + public function studentAdvice(): Link + { + return $this->studentAdvice; + } + + public function subjectSpecificAdvice(): Link + { + return $this->subjectSpecificAdvice; + } + + public function serviceCenters(): Link + { + return $this->serviceCenters; + } + + public function infoBrochure(): string + { + return $this->infoBrochure; + } + + public function semesterFee(): Link + { + return $this->semesterFee; + } + + public function degreeProgramFees(): string + { + return $this->degreeProgramFees; + } + + public function abroadOpportunities(): Link + { + return $this->abroadOpportunities; + } + + public function keywords(): ArrayOfStrings + { + return $this->keywords; + } + + public function areaOfStudy(): Links + { + return $this->areaOfStudy; + } + + public function combinations(): RelatedDegreePrograms + { + return $this->combinations; + } + + public function limitedCombinations(): RelatedDegreePrograms + { + return $this->limitedCombinations; + } + + public function notesForInternationalApplicants(): Link + { + return $this->notesForInternationalApplicants; + } + + public function studentInitiatives(): Link + { + return $this->studentInitiatives; + } + + public function applyNowLink(): Link + { + return $this->applyNowLink; + } + + public function entryText(): string + { + return $this->entryText; + } + + public function campoKeys(): CampoKeys + { + return $this->campoKeys; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/DegreeTranslated.php b/vendor/rrze/fau-studium-common/src/Application/DegreeTranslated.php new file mode 100644 index 000000000..3a590cac9 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/DegreeTranslated.php @@ -0,0 +1,92 @@ +name()->asString($languageCode), + $degree->abbreviation()->asString($languageCode), + $degree->parent() ? self::fromDegree($degree->parent(), $languageCode) : null, + ); + } + + /** + * @psalm-param DegreeTranslatedType $data + */ + public static function fromArray(array $data): self + { + /** @var DegreeTranslatedType|null $parentData */ + $parentData = $data[Degree::PARENT]; + return new self( + $data[Degree::NAME], + $data[Degree::ABBREVIATION], + !empty($parentData) ? self::fromArray($parentData) : null, + ); + } + + /** + * @return DegreeTranslatedType + */ + public function asArray(): array + { + /** @var DegreeTranslated|null $parentData */ + $parentData = $this->parent?->asArray(); + return [ + Degree::NAME => $this->name, + Degree::ABBREVIATION => $this->abbreviation, + Degree::PARENT => $parentData, + ]; + } + + public function name(): string + { + return $this->name; + } + + public function abbreviation(): string + { + return $this->abbreviation; + } + + public function parent(): ?DegreeTranslated + { + return $this->parent; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Event/CacheInvalidated.php b/vendor/rrze/fau-studium-common/src/Application/Event/CacheInvalidated.php new file mode 100644 index 000000000..c94b7dace --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Event/CacheInvalidated.php @@ -0,0 +1,52 @@ + $ids + */ + private function __construct( + private bool $isFully, + private array $ids, + ) { + } + + public static function fully(): self + { + return new self(true, []); + } + + /** + * @param array $ids + */ + public static function partially(array $ids): self + { + return new self(false, $ids); + } + + public function isFully(): bool + { + return $this->isFully; + } + + /** + * @return array + */ + public function ids(): array + { + return $this->ids; + } + + public function __toString(): string + { + return self::NAME; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Event/CacheWarmed.php b/vendor/rrze/fau-studium-common/src/Application/Event/CacheWarmed.php new file mode 100644 index 000000000..b73fd6019 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Event/CacheWarmed.php @@ -0,0 +1,52 @@ + $ids + */ + private function __construct( + private bool $isFully, + private array $ids, + ) { + } + + public static function fully(): self + { + return new self(true, []); + } + + /** + * @param array $ids + */ + public static function partially(array $ids): self + { + return new self(false, $ids); + } + + public function isFully(): bool + { + return $this->isFully; + } + + /** + * @return array + */ + public function ids(): array + { + return $this->ids; + } + + public function __toString(): string + { + return self::NAME; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Filter/AdmissionRequirementTypeFilter.php b/vendor/rrze/fau-studium-common/src/Application/Filter/AdmissionRequirementTypeFilter.php new file mode 100644 index 000000000..47036f429 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Filter/AdmissionRequirementTypeFilter.php @@ -0,0 +1,66 @@ + + */ + private array $types; + + private function __construct( + string ...$types + ) { + + $this->types = $types; + } + + public function id(): string + { + return self::KEY; + } + + public function value(): array + { + return array_unique($this->types); + } + + public static function fromInput(mixed $value): static + { + $sanitizedValue = self::sanitize($value); + + return $sanitizedValue ? new self(...$sanitizedValue) : self::empty(); + } + + public static function empty(): static + { + return new self(); + } + + /** + * @return array|null + */ + private static function sanitize(mixed $value): ?array + { + if (is_string($value)) { + $value = explode(',', $value); + } + + if (!is_array($value)) { + return null; + } + + return array_filter( + $value, + 'is_string', + ); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Filter/AreaOfStudyFilter.php b/vendor/rrze/fau-studium-common/src/Application/Filter/AreaOfStudyFilter.php new file mode 100644 index 000000000..0cf1e0016 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Filter/AreaOfStudyFilter.php @@ -0,0 +1,17 @@ + + */ + private array $ids; + + private function __construct( + int ...$ids + ) { + + $this->ids = $ids; + } + + public function value(): array + { + return $this->ids; + } + + public static function fromInput(mixed $value): static + { + $sanitizedValue = self::sanitize($value); + + return $sanitizedValue ? new self(...$sanitizedValue) : self::empty(); + } + + public static function empty(): static + { + return new self(); + } + + /** + * @return array|null + */ + private static function sanitize(mixed $value): ?array + { + if (is_string($value)) { + $value = explode(',', $value); + } + + if (!is_array($value)) { + return null; + } + + $sanitizedArray = array_filter(array_map('intval', $value)); + return $sanitizedArray; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Filter/AttributeFilter.php b/vendor/rrze/fau-studium-common/src/Application/Filter/AttributeFilter.php new file mode 100644 index 000000000..3ae0a00af --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Filter/AttributeFilter.php @@ -0,0 +1,17 @@ + AdmissionRequirementTypeFilter::class, + AreaOfStudyFilter::KEY => AreaOfStudyFilter::class, + AttributeFilter::KEY => AttributeFilter::class, + DegreeFilter::KEY => DegreeFilter::class, + FacultyFilter::KEY => FacultyFilter::class, + GermanLanguageSkillsForInternationalStudentsFilter::KEY => GermanLanguageSkillsForInternationalStudentsFilter::class, + SearchKeywordFilter::KEY => SearchKeywordFilter::class, + SemesterFilter::KEY => SemesterFilter::class, + StudyLocationFilter::KEY => StudyLocationFilter::class, + SubjectGroupFilter::KEY => SubjectGroupFilter::class, + TeachingLanguageFilter::KEY => TeachingLanguageFilter::class, + ]; + + public function create(string $filterName, mixed $value): ?Filter + { + $className = self::SUPPORTED_FILTERS[$filterName] ?? null; + + if (!$className) { + return null; + } + + if ($value === null) { + return $className::empty(); + } + + /** + * @var Filter $filter + * phpcs:disable NeutronStandard.Functions.DisallowCallUserFunc.CallUserFunc + */ + $filter = call_user_func([$className, 'fromInput'], $value); + return $filter; + } + + /** + * @param array $list + * @return array + */ + public function bulk(array $list): array + { + $result = []; + foreach ($list as $name => $value) { + $result[] = $this->create($name, $value); + } + + return array_filter($result); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Filter/GermanLanguageSkillsForInternationalStudentsFilter.php b/vendor/rrze/fau-studium-common/src/Application/Filter/GermanLanguageSkillsForInternationalStudentsFilter.php new file mode 100644 index 000000000..a8b7e6b80 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Filter/GermanLanguageSkillsForInternationalStudentsFilter.php @@ -0,0 +1,17 @@ +keyword; + } + + public function id(): string + { + return self::KEY; + } + + public static function fromInput(mixed $value): static + { + $sanitizedValue = self::sanitize($value); + return $sanitizedValue ? new self($sanitizedValue) : self::empty(); + } + + public static function empty(): static + { + return new self(''); + } + + private static function sanitize(mixed $value): ?string + { + return is_string($value) ? $value : null; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Filter/SemesterFilter.php b/vendor/rrze/fau-studium-common/src/Application/Filter/SemesterFilter.php new file mode 100644 index 000000000..a14f54f27 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Filter/SemesterFilter.php @@ -0,0 +1,17 @@ + $this->id, + Image::URL => $this->url, + self::RENDERED => $this->rendered, + ]; + } + + public function id(): int + { + return $this->id; + } + + public function url(): string + { + return $this->url; + } + + public function rendered(): string + { + return $this->rendered; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/JsonSerializer/CouldNotDeserialize.php b/vendor/rrze/fau-studium-common/src/Application/JsonSerializer/CouldNotDeserialize.php new file mode 100644 index 000000000..a36aa9e9b --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/JsonSerializer/CouldNotDeserialize.php @@ -0,0 +1,28 @@ +name()->asString($languageCode), + $multilingualLink->linkText()->asString($languageCode), + $multilingualLink->linkUrl()->asString($languageCode), + ); + } + + /** + * @psalm-param LinkType $data + */ + public static function fromArray(array $data): self + { + return new self( + $data[MultilingualLink::NAME], + $data[MultilingualLink::LINK_TEXT], + $data[MultilingualLink::LINK_URL], + ); + } + + public function name(): string + { + return $this->name; + } + + public function linkText(): string + { + return $this->linkText; + } + + public function linkUrl(): string + { + return $this->linkUrl; + } + + /** + * @return LinkType $data + */ + public function asArray(): array + { + return [ + MultilingualLink::NAME => $this->name, + MultilingualLink::LINK_TEXT => $this->linkText, + MultilingualLink::LINK_URL => $this->linkUrl, + ]; + } + + public function asHtml(): string + { + $linkText = $this->linkText ?: $this->name; + + if ($linkText && $this->linkUrl) { + return sprintf( + '%s', + $this->linkUrl, + $linkText + ); + } + + if ($linkText) { + return $linkText; + } + + return ''; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Links.php b/vendor/rrze/fau-studium-common/src/Application/Links.php new file mode 100644 index 000000000..3b2f7dd1d --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Links.php @@ -0,0 +1,65 @@ + + * @psalm-import-type LinkType from Link + */ +final class Links extends ArrayObject +{ + private function __construct(Link ...$links) + { + parent::__construct($links); + } + + public static function new(Link ...$links): self + { + return new self(...$links); + } + + public static function fromMultilingualLinks(MultilingualLinks $multilingualLinks, string $languageCode): self + { + return new self( + ...array_map( + static fn(MultilingualLink $multilingualLink) => Link::fromMultilingualLink($multilingualLink, $languageCode), + $multilingualLinks->getArrayCopy() + ) + ); + } + + /** + * @param array $items + */ + public static function fromArray(array $items): self + { + return new self( + ...array_map([Link::class, 'fromArray'], $items) + ); + } + + /** + * @return array + */ + public function asArray(): array + { + return array_map( + static fn(Link $link) => $link->asArray(), + $this->getArrayCopy() + ); + } + + public function asHtml(): string + { + return implode(', ', array_map( + static fn(Link $link) => $link->asHtml(), + $this->getArrayCopy() + )); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Queue/Message.php b/vendor/rrze/fau-studium-common/src/Application/Queue/Message.php new file mode 100644 index 000000000..083781d2b --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Queue/Message.php @@ -0,0 +1,9 @@ +> $handlers + */ + public function __construct( + private JsonSerializer $serializer, + private iterable $handlers + ) { + } + + public function handle(string|Message $message): void + { + /** @var Message $messageObject */ + $messageObject = is_string($message) ? $this->serializer->deserialize($message) : $message; + $handlers = $this->provide($messageObject); + + foreach ($handlers as $handler) { + $handler($messageObject); + } + } + + /** + * @return array + */ + private function provide(Message $message): iterable + { + return $this->handlers[get_class($message)] ?? []; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/RelatedDegreeProgram.php b/vendor/rrze/fau-studium-common/src/Application/RelatedDegreeProgram.php new file mode 100644 index 000000000..9151872e5 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/RelatedDegreeProgram.php @@ -0,0 +1,73 @@ +title; + } + + public function url(): string + { + return $this->url; + } + + /** + * @psalm-return RelatedDegreeProgramType + */ + public function asArray(): array + { + return [ + self::ID => $this->id, + self::TITLE => $this->title, + self::URL => $this->url, + ]; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/RelatedDegreePrograms.php b/vendor/rrze/fau-studium-common/src/Application/RelatedDegreePrograms.php new file mode 100644 index 000000000..7fc914dbb --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/RelatedDegreePrograms.php @@ -0,0 +1,54 @@ + + * @psalm-import-type RelatedDegreeProgramType from RelatedDegreeProgram + */ +final class RelatedDegreePrograms extends ArrayObject implements JsonSerializable +{ + private function __construct(RelatedDegreeProgram ...$relatedDegreePrograms) + { + parent::__construct($relatedDegreePrograms); + } + + public static function new(RelatedDegreeProgram ...$relatedDegreePrograms): self + { + return new self(...$relatedDegreePrograms); + } + + /** + * @psalm-param array $data + */ + public static function fromArray(array $data): self + { + return new self( + ...array_map( + [RelatedDegreeProgram::class, 'fromArray'], + $data + ) + ); + } + + /** + * @return array + */ + public function asArray(): array + { + return array_map( + static fn(RelatedDegreeProgram $relatedDegreeProgram) => $relatedDegreeProgram->asArray(), + $this->getArrayCopy() + ); + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Repository/CachedDegreeProgramViewRepository.php b/vendor/rrze/fau-studium-common/src/Application/Repository/CachedDegreeProgramViewRepository.php new file mode 100644 index 000000000..fc69916d6 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Repository/CachedDegreeProgramViewRepository.php @@ -0,0 +1,52 @@ +cacheKeyGenerator->generateForDegreeProgram($degreeProgramId); + /** @psalm-var ?DegreeProgramViewRawArrayType $data */ + $data = $this->cache->get($key); + + return is_array($data) + ? DegreeProgramViewRaw::fromArray($data) + : $this->decorated->findRaw($degreeProgramId); + } + + public function findTranslated(DegreeProgramId $degreeProgramId, string $languageCode): ?DegreeProgramViewTranslated + { + $key = $this->cacheKeyGenerator->generateForDegreeProgram($degreeProgramId, CacheKeyGenerator::TRANSLATED_TYPE); + /** @psalm-var ?DegreeProgramViewTranslatedArrayType $data */ + $data = $this->cache->get($key); + + if (!is_array($data)) { + return $this->decorated->findTranslated($degreeProgramId, $languageCode); + } + + return DegreeProgramViewTranslated::fromArray($data) + ->withBaseLang($languageCode); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Repository/CollectionCriteria.php b/vendor/rrze/fau-studium-common/src/Application/Repository/CollectionCriteria.php new file mode 100644 index 000000000..53dd38354 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Repository/CollectionCriteria.php @@ -0,0 +1,213 @@ + + * @psalm-type SupportedArgs = array{ + * page: int, + * per_page: int, + * include?: array, + * search?: string, + * order_by: OrderBy, + * his_codes?: array + * } + */ +final class CollectionCriteria +{ + public const SORTABLE_PROPERTIES = [ + DegreeProgram::TITLE, + DegreeProgram::DEGREE, + DegreeProgram::START, + DegreeProgram::LOCATION, + DegreeProgram::ADMISSION_REQUIREMENTS, + DegreeProgram::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS, + ]; + + /** + * @var Filter[] + */ + private array $filters = []; + + /** + * @var array + */ + private array $hisCodes = []; + + /** + * @var LanguageCodes|null + */ + private ?string $languageCode = null; + + /** + * @param SupportedArgs $args + */ + private function __construct( + private array $args, + ) { + } + + public static function new(): self + { + return new self([ + 'page' => 1, + 'per_page' => 10, + 'order_by' => [], + ]); + } + + public function toNextPage(): self + { + $instance = clone $this; + $instance->args['page']++; + + return $instance; + } + + public function withPage(int $page): self + { + Assert::positiveInteger($page); + + $instance = clone $this; + $instance->args['page'] = $page; + + return $instance; + } + + public function page(): int + { + return $this->args['page']; + } + + public function withPerPage(int $perPage): self + { + Assert::greaterThanEq($perPage, -1); + Assert::notEq($perPage, 0); + + $instance = clone $this; + $instance->args['per_page'] = $perPage; + + return $instance; + } + + public function perPage(): int + { + return $this->args['per_page']; + } + + /** + * @psalm-return LanguageCodes|null + */ + public function languageCode(): ?string + { + return $this->languageCode; + } + + public function addFilter(Filter ...$filters): self + { + $this->filters = array_merge( + $this->filters(), + array_filter( + $filters, + static fn (Filter $filter) => !empty($filter->value()), + ) + ); + + return $this; + } + + public function withoutPagination(): self + { + $instance = clone $this; + $instance->args['per_page'] = -1; + + return $instance; + } + + /** + * @param array $include + */ + public function withInclude(array $include): self + { + Assert::allPositiveInteger($include); + + $instance = clone $this; + $instance->args['include'] = $include; + + return $instance; + } + + /** + * @psalm-param LanguageCodes $languageCode + */ + public function withLanguage(string $languageCode): self + { + $instance = clone $this; + + $instance->languageCode = $languageCode; + + return $instance; + } + + /** + * @psalm-param OrderBy $orderBy + */ + public function withOrderBy(array $orderBy): self + { + $instance = clone $this; + $sanitizedValue = []; + foreach ($orderBy as $property => $order) { + if (!in_array($property, self::SORTABLE_PROPERTIES, true)) { + continue; + } + + $sanitizedValue[$property] = $order === 'asc' ? 'asc' : 'desc'; + } + + $instance->args['order_by'] = $sanitizedValue; + return $instance; + } + + /** + * @param array $hisCodes + * @return self + */ + public function withHisCodes(array $hisCodes): self + { + $instance = clone $this; + $instance->hisCodes = $hisCodes; + return $instance; + } + + /** + * @psalm-return SupportedArgs + */ + public function args(): array + { + return $this->args; + } + + /** + * @psalm-return Filter[] + */ + public function filters(): array + { + return $this->filters; + } + + /** + * @return array + */ + public function hisCodes(): array + { + return $this->hisCodes; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Repository/DegreeProgramCollectionRepository.php b/vendor/rrze/fau-studium-common/src/Application/Repository/DegreeProgramCollectionRepository.php new file mode 100644 index 000000000..e3390a0e8 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Repository/DegreeProgramCollectionRepository.php @@ -0,0 +1,31 @@ +|null + * Null in case we could not find the collection for external reasons. + */ + public function findRawCollection(CollectionCriteria $criteria): ?PaginationAwareCollection; + + /** + * @psalm-param LanguageCodes $languageCode + * @psalm-return PaginationAwareCollection|null + * Null in case we could not find the collection for external reasons. + */ + public function findTranslatedCollection( + CollectionCriteria $criteria, + string $languageCode + ): ?PaginationAwareCollection; +} diff --git a/vendor/rrze/fau-studium-common/src/Application/Repository/DegreeProgramCombinationRepository.php b/vendor/rrze/fau-studium-common/src/Application/Repository/DegreeProgramCombinationRepository.php new file mode 100644 index 000000000..a2baf008d --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Application/Repository/DegreeProgramCombinationRepository.php @@ -0,0 +1,9 @@ + + */ +interface PaginationAwareCollection extends Traversable +{ + public function currentPage(): int; + + public function nextPage(): ?int; + + public function previousPage(): ?int; + + public function maxPages(): int; + + public function totalItems(): int; +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/AdmissionRequirement.php b/vendor/rrze/fau-studium-common/src/Domain/AdmissionRequirement.php new file mode 100644 index 000000000..fe84c9ecc --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/AdmissionRequirement.php @@ -0,0 +1,220 @@ + 'object', + 'additionalProperties' => false, + 'required' => [ + AdmissionRequirement::ID, + AdmissionRequirement::NAME, + AdmissionRequirement::SLUG, + AdmissionRequirement::LINK_TEXT, + AdmissionRequirement::LINK_URL, + AdmissionRequirement::PARENT, + ], + 'properties' => [ + AdmissionRequirement::ID => [ + 'type' => 'string', + 'minLength' => 1, + ], + AdmissionRequirement::NAME => MultilingualString::SCHEMA, + AdmissionRequirement::SLUG => [ + 'type' => 'string', + 'minLength' => 1, + ], + AdmissionRequirement::LINK_TEXT => MultilingualString::SCHEMA, + AdmissionRequirement::LINK_URL => MultilingualString::SCHEMA, + AdmissionRequirement::PARENT => [ + 'type' => 'object', + 'additionalProperties' => true, + 'required' => [ + AdmissionRequirement::ID, + AdmissionRequirement::NAME, + AdmissionRequirement::SLUG, + ], + 'properties' => [ + AdmissionRequirement::ID => [ + 'type' => 'string', + 'minLength' => 1, + ], + AdmissionRequirement::NAME => MultilingualString::SCHEMA, + AdmissionRequirement::SLUG => [ + 'type' => 'string', + 'minLength' => 1, + ], + ], + ], + ], + ]; + + public const SCHEMA_EMPTY = [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => [ + AdmissionRequirement::ID, + AdmissionRequirement::NAME, + AdmissionRequirement::SLUG, + AdmissionRequirement::LINK_TEXT, + AdmissionRequirement::LINK_URL, + ], + 'properties' => [ + AdmissionRequirement::ID => [ + 'type' => 'string', + 'maxLength' => 0, + ], + AdmissionRequirement::NAME => MultilingualString::SCHEMA, + AdmissionRequirement::SLUG => [ + 'type' => 'string', + 'maxLength' => 0, + ], + AdmissionRequirement::LINK_TEXT => MultilingualString::SCHEMA, + AdmissionRequirement::LINK_URL => MultilingualString::SCHEMA, + AdmissionRequirement::PARENT => [ + 'type' => 'null', + ], + ], + ]; + + private function __construct( + private MultilingualLink $current, + private ?AdmissionRequirement $parent, + private string $slug + ) { + } + + public static function new( + MultilingualLink $current, + ?AdmissionRequirement $parent, + string $slug = '' + ): self { + + return new self($current, $parent, $slug); + } + + public static function empty(): self + { + return new self( + MultilingualLink::empty(), + null, + '' + ); + } + + /** + * @psalm-param AdmissionRequirementType $data + */ + public static function fromArray(array $data): self + { + $currentData = [ + self::ID => $data[self::ID], + self::NAME => $data[self::NAME], + self::LINK_TEXT => $data[self::LINK_TEXT], + self::LINK_URL => $data[self::LINK_URL], + ]; + + /** @var AdmissionRequirementType|null $parentData */ + $parentData = $data[self::PARENT] ?? null; + $slug = $data[self::SLUG] ?? ''; + + return new self( + MultilingualLink::fromArray($currentData), + $parentData ? self::fromArray($parentData) : null, + $slug + ); + } + + /** + * @return AdmissionRequirementType + */ + public function asArray(): array + { + /** @var AdmissionRequirement|null $parentData */ + $parentData = $this->parent?->asArray(); + $currentData = $this->current->asArray(); + $currentData[self::PARENT] = $parentData; + $currentData[self::SLUG] = $this->slug; + + return $currentData; + } + + public function id(): string + { + return $this->current->id(); + } + + public function name(): MultilingualString + { + return $this->current->name(); + } + + public function slug(): string + { + return $this->slug; + } + + public function linkText(): MultilingualString + { + return $this->current->linkText(); + } + + public function linkUrl(): MultilingualString + { + return $this->current->linkUrl(); + } + + public function parent(): ?AdmissionRequirement + { + return $this->parent; + } + + public function isEmpty(): bool + { + return !$this->current->id(); + } + + public function current(): MultilingualLink + { + return $this->current; + } + + public function hasGermanName(string $name): bool + { + if ($this->name()->inGerman() === $name) { + return true; + } + + if (!$this->parent) { + return false; + } + + return $this->parent->name()->inGerman() === $name; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/AdmissionRequirements.php b/vendor/rrze/fau-studium-common/src/Domain/AdmissionRequirements.php new file mode 100644 index 000000000..6b23e205e --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/AdmissionRequirements.php @@ -0,0 +1,88 @@ + $this->bachelorOrTeachingDegree->asArray(), + self::TEACHING_DEGREE_HIGHER_SEMESTER => $this->teachingDegreeHigherSemester->asArray(), + self::MASTER => $this->master->asArray(), + ]; + } + + public function bachelorOrTeachingDegree(): AdmissionRequirement + { + return $this->bachelorOrTeachingDegree; + } + + public function teachingDegreeHigherSemester(): AdmissionRequirement + { + return $this->teachingDegreeHigherSemester; + } + + public function master(): AdmissionRequirement + { + return $this->master; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/CampoKeys.php b/vendor/rrze/fau-studium-common/src/Domain/CampoKeys.php new file mode 100644 index 000000000..7788684ac --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/CampoKeys.php @@ -0,0 +1,90 @@ +, string> + */ +final class CampoKeys +{ + public const SCHEMA = [ + 'type' => 'object', + 'properties' => [ + DegreeProgram::DEGREE => [ + 'type' => 'string', + ], + DegreeProgram::AREA_OF_STUDY => [ + 'type' => 'string', + ], + DegreeProgram::LOCATION => [ + 'type' => 'string', + ], + ], + ]; + + public const SCHEMA_REQUIRED = [ + 'type' => 'object', + 'properties' => [ + DegreeProgram::DEGREE => [ + 'type' => 'string', + ], + DegreeProgram::AREA_OF_STUDY => [ + 'type' => 'string', + ], + DegreeProgram::LOCATION => [ + 'type' => 'string', + ], + ], + ]; + + public const SUPPORTED_CAMPO_KEYS = [ + DegreeProgram::DEGREE, + DegreeProgram::AREA_OF_STUDY, + DegreeProgram::LOCATION, + ]; + + private const HIS_CODE_DELIMITER = '|'; + + private function __construct( + /** + * @var CampoKeysMap $map + */ + private array $map + ) { + } + + public static function empty(): self + { + return new self([]); + } + + /** + * @param CampoKeysMap $map + */ + public static function fromArray(array $map): self + { + return new self($map); + } + + public static function fromHisCode(string $hisCode): self + { + $parts = explode(self::HIS_CODE_DELIMITER, $hisCode); + $map = [ + DegreeProgram::DEGREE => $parts[0] ?? null, + DegreeProgram::AREA_OF_STUDY => $parts[1] ?? null, + DegreeProgram::LOCATION => $parts[6] ?? null, + ]; + + return new self(array_filter($map, fn($value) => !is_null($value))); + } + + /** + * @return CampoKeysMap + */ + public function asArray(): array + { + return $this->map; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/Content.php b/vendor/rrze/fau-studium-common/src/Domain/Content.php new file mode 100644 index 000000000..b880a213e --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/Content.php @@ -0,0 +1,223 @@ +about = $this->about->withDefaultTitle( + MultilingualString::fromTranslations( + 'default', + 'Worum geht es im Studiengang?', + 'What is the degree program about?', + ) + ); + + $this->structure = $this->structure->withDefaultTitle( + MultilingualString::fromTranslations( + 'default', + 'Aufbau und Struktur', + 'Design and structure', + ) + ); + + $this->specializations = $this->specializations->withDefaultTitle( + MultilingualString::fromTranslations( + 'default', + 'Studienrichtungen und Schwerpunkte', + 'Fields of study and specializations', + ) + ); + + $this->qualitiesAndSkills = $this->qualitiesAndSkills->withDefaultTitle( + MultilingualString::fromTranslations( + 'default', + 'Was sollte ich mitbringen?', + 'Which qualities and skills do I need?', + ) + ); + + $this->whyShouldStudy = $this->whyShouldStudy->withDefaultTitle( + MultilingualString::fromTranslations( + 'default', + 'Gute Gründe für ein Studium an der FAU', + 'Why should I study at FAU?', + ) + ); + + $this->careerProspects = $this->careerProspects->withDefaultTitle( + MultilingualString::fromTranslations( + 'default', + 'Welche beruflichen Perspektiven stehen mir offen?', + 'Which career prospects are open to me?', + ) + ); + + $this->specialFeatures = $this->specialFeatures->withDefaultTitle( + MultilingualString::fromTranslations( + 'default', + 'Besondere Hinweise', + 'Special features', + ) + ); + + $this->testimonials = $this->testimonials->withDefaultTitle( + MultilingualString::fromTranslations( + 'default', + 'Erfahrungsberichte', + 'Testimonials', + ) + ); + } + + public static function new( + ContentItem $about, + ContentItem $structure, + ContentItem $specializations, + ContentItem $qualitiesAndSkills, + ContentItem $whyShouldStudy, + ContentItem $careerProspects, + ContentItem $specialFeatures, + ContentItem $testimonials + ): self { + + return new self( + $about, + $structure, + $specializations, + $qualitiesAndSkills, + $whyShouldStudy, + $careerProspects, + $specialFeatures, + $testimonials + ); + } + + /** + * @psalm-param ContentType $data + */ + public static function fromArray(array $data): self + { + return new self( + ContentItem::fromArray($data[self::ABOUT]), + ContentItem::fromArray($data[self::STRUCTURE]), + ContentItem::fromArray($data[self::SPECIALIZATIONS]), + ContentItem::fromArray($data[self::QUALITIES_AND_SKILLS]), + ContentItem::fromArray($data[self::WHY_SHOULD_STUDY]), + ContentItem::fromArray($data[self::CAREER_PROSPECTS]), + ContentItem::fromArray($data[self::SPECIAL_FEATURES]), + ContentItem::fromArray($data[self::TESTIMONIALS]), + ); + } + + /** + * @return ContentType + */ + public function asArray(): array + { + return [ + self::ABOUT => $this->about->asArray(), + self::STRUCTURE => $this->structure->asArray(), + self::SPECIALIZATIONS => $this->specializations->asArray(), + self::QUALITIES_AND_SKILLS => $this->qualitiesAndSkills->asArray(), + self::WHY_SHOULD_STUDY => $this->whyShouldStudy->asArray(), + self::CAREER_PROSPECTS => $this->careerProspects->asArray(), + self::SPECIAL_FEATURES => $this->specialFeatures->asArray(), + self::TESTIMONIALS => $this->testimonials->asArray(), + ]; + } + + /** + * @psalm-param ContentType $data + * @psalm-param callable(string): string $callback + * @psalm-return ContentType + */ + public static function mapDescriptions(array $data, callable $callback): array + { + foreach ($data as $key => $item) { + foreach ([MultilingualString::DE, MultilingualString::EN] as $languageCode) { + $data[$key][ContentItem::DESCRIPTION][$languageCode] = $callback( + $item[ContentItem::DESCRIPTION][$languageCode] + ); + } + } + return $data; + } + + public function about(): ContentItem + { + return $this->about; + } + + public function structure(): ContentItem + { + return $this->structure; + } + + public function specializations(): ContentItem + { + return $this->specializations; + } + + public function qualitiesAndSkills(): ContentItem + { + return $this->qualitiesAndSkills; + } + + public function whyShouldStudy(): ContentItem + { + return $this->whyShouldStudy; + } + + public function careerProspects(): ContentItem + { + return $this->careerProspects; + } + + public function specialFeatures(): ContentItem + { + return $this->specialFeatures; + } + + public function testimonials(): ContentItem + { + return $this->testimonials; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/ContentItem.php b/vendor/rrze/fau-studium-common/src/Domain/ContentItem.php new file mode 100644 index 000000000..d1b3d8b93 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/ContentItem.php @@ -0,0 +1,103 @@ + 'object', + 'additionalProperties' => false, + 'required' => [ContentItem::TITLE, ContentItem::DESCRIPTION], + 'properties' => [ + ContentItem::TITLE => MultilingualString::SCHEMA, + ContentItem::DESCRIPTION => MultilingualString::SCHEMA, + ], + ]; + + public const SCHEMA_REQUIRED = [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => [ContentItem::TITLE, ContentItem::DESCRIPTION], + 'properties' => [ + ContentItem::TITLE => MultilingualString::SCHEMA, + ContentItem::DESCRIPTION => MultilingualString::SCHEMA_REQUIRED, + ], + ]; + + private function __construct( + private MultilingualString $title, + private MultilingualString $description, + ?MultilingualString $defaultTitle, + ) { + + if ($defaultTitle instanceof MultilingualString) { + $this->title = $this->title->mergeWithDefault($defaultTitle); + } + } + + public static function new( + MultilingualString $title, + MultilingualString $description, + ): self { + + return new self( + $title, + $description, + null, + ); + } + + /** + * @psalm-param ContentItemType $data + */ + public static function fromArray(array $data): self + { + return new self( + MultilingualString::fromArray($data[self::TITLE]), + MultilingualString::fromArray($data[self::DESCRIPTION]), + null, + ); + } + + /** + * @return ContentItemType + */ + public function asArray(): array + { + return [ + self::TITLE => $this->title->asArray(), + self::DESCRIPTION => $this->description->asArray(), + ]; + } + + public function withDefaultTitle(MultilingualString $defaultTitle): self + { + return new self( + $this->title, + $this->description, + $defaultTitle + ); + } + + public function title(): MultilingualString + { + return $this->title; + } + + public function description(): MultilingualString + { + return $this->description; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/Degree.php b/vendor/rrze/fau-studium-common/src/Domain/Degree.php new file mode 100644 index 000000000..012fe7fbf --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/Degree.php @@ -0,0 +1,175 @@ + 'object', + 'additionalProperties' => true, + 'required' => [ + Degree::ID, + Degree::NAME, + Degree::ABBREVIATION, + ], + 'properties' => [ + Degree::ID => [ + 'type' => 'string', + ], + Degree::NAME => MultilingualString::SCHEMA, + Degree::ABBREVIATION => MultilingualString::SCHEMA, + ], + ]; + + public const SCHEMA_REQUIRED = [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => [ + Degree::ID, + Degree::NAME, + Degree::ABBREVIATION, + Degree::PARENT, + ], + 'properties' => [ + Degree::ID => [ + 'type' => 'string', + 'minLength' => 1, + ], + Degree::NAME => MultilingualString::SCHEMA, + Degree::ABBREVIATION => MultilingualString::SCHEMA, + Degree::PARENT => [ + 'type' => 'object', + 'additionalProperties' => true, + 'required' => [Degree::ID], + 'properties' => [ + Degree::ID => [ + 'type' => 'string', + 'minLength' => 1, + ], + ], + ], + ], + ]; + + private function __construct( + private string $id, + private MultilingualString $name, + private MultilingualString $abbreviation, + private ?Degree $parent, + ) { + } + + public static function new( + string $id, + MultilingualString $name, + MultilingualString $abbreviation, + ?Degree $parent, + ): self { + + return new self( + $id, + $name, + $abbreviation, + $parent + ); + } + + public static function empty(): self + { + return new self( + '', + MultilingualString::empty(), + MultilingualString::empty(), + null, + ); + } + + /** + * @psalm-param DegreeType $data + */ + public static function fromArray(array $data): self + { + /** @var DegreeType|null $parentData */ + $parentData = $data[self::PARENT] ?? null; + return new self( + $data[self::ID], + MultilingualString::fromArray($data[self::NAME]), + MultilingualString::fromArray($data[self::ABBREVIATION]), + !empty($parentData) ? self::fromArray($parentData) : null, + ); + } + + /** + * @return DegreeType + */ + public function asArray(): array + { + /** @var Degree|null $parentData */ + $parentData = $this->parent?->asArray(); + return [ + self::ID => $this->id, + self::NAME => $this->name->asArray(), + self::ABBREVIATION => $this->abbreviation->asArray(), + self::PARENT => $parentData, + ]; + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } + + public function id(): string + { + return $this->id; + } + + public function name(): MultilingualString + { + return $this->name; + } + + public function abbreviation(): MultilingualString + { + return $this->abbreviation; + } + + public function parent(): ?Degree + { + return $this->parent; + } + + public function hasGermanAbbreviation(string $abbreviation): bool + { + if ($this->abbreviation->inGerman() === $abbreviation) { + return true; + } + + if (!$this->parent) { + return false; + } + + return $this->parent->abbreviation->inGerman() === $abbreviation; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/DegreeProgram.php b/vendor/rrze/fau-studium-common/src/Domain/DegreeProgram.php new file mode 100644 index 000000000..e3e724394 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/DegreeProgram.php @@ -0,0 +1,597 @@ +, + * number_of_students: NumberOfStudentsType, + * teaching_language: MultilingualStringType, + * attributes: array, + * degree: DegreeType, + * faculty: array, + * location: array, + * subject_groups: array, + * videos: array, + * meta_description: MultilingualStringType, + * content: ContentType, + * admission_requirements: AdmissionRequirementsType, + * content_related_master_requirements: MultilingualStringType, + * application_deadline_winter_semester: string, + * application_deadline_summer_semester: string, + * details_and_notes: MultilingualStringType, + * language_skills: MultilingualStringType, + * language_skills_humanities_faculty: string, + * german_language_skills_for_international_students: MultilingualLinkType, + * start_of_semester: MultilingualLinkType, + * semester_dates: MultilingualLinkType, + * examinations_office: MultilingualLinkType, + * examination_regulations: string, + * module_handbook: string, + * url: MultilingualStringType, + * department: MultilingualStringType, + * student_advice: MultilingualLinkType, + * subject_specific_advice: MultilingualLinkType, + * service_centers: MultilingualLinkType, + * info_brochure: string, + * semester_fee: MultilingualLinkType, + * degree_program_fees: MultilingualStringType, + * abroad_opportunities: MultilingualLinkType, + * keywords: array, + * area_of_study: array, + * combinations: array, + * limited_combinations: array, + * notes_for_international_applicants: MultilingualLinkType, + * student_initiatives: MultilingualLinkType, + * apply_now_link: MultilingualLinkType, + * entry_text: MultilingualStringType, + * campo_keys: CampoKeysMap, + * } + */ +final class DegreeProgram +{ + public const ID = 'id'; + public const SLUG = 'slug'; + public const FEATURED_IMAGE = 'featured_image'; + public const TEASER_IMAGE = 'teaser_image'; + public const TITLE = 'title'; + public const SUBTITLE = 'subtitle'; + public const STANDARD_DURATION = 'standard_duration'; + public const FEE_REQUIRED = 'fee_required'; + public const START = 'start'; + public const NUMBER_OF_STUDENTS = 'number_of_students'; + public const TEACHING_LANGUAGE = 'teaching_language'; + public const ATTRIBUTES = 'attributes'; + public const DEGREE = 'degree'; + public const FACULTY = 'faculty'; + public const LOCATION = 'location'; + public const SUBJECT_GROUPS = 'subject_groups'; + public const VIDEOS = 'videos'; + public const META_DESCRIPTION = 'meta_description'; + public const CONTENT = 'content'; + public const ADMISSION_REQUIREMENTS = 'admission_requirements'; + public const CONTENT_RELATED_MASTER_REQUIREMENTS = 'content_related_master_requirements'; + public const APPLICATION_DEADLINE_WINTER_SEMESTER = 'application_deadline_winter_semester'; + public const APPLICATION_DEADLINE_SUMMER_SEMESTER = 'application_deadline_summer_semester'; + public const DETAILS_AND_NOTES = 'details_and_notes'; + public const LANGUAGE_SKILLS = 'language_skills'; + public const LANGUAGE_SKILLS_HUMANITIES_FACULTY = 'language_skills_humanities_faculty'; + public const GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS = 'german_language_skills_for_international_students'; + public const START_OF_SEMESTER = 'start_of_semester'; + public const SEMESTER_DATES = 'semester_dates'; + public const EXAMINATIONS_OFFICE = 'examinations_office'; + public const EXAMINATION_REGULATIONS = 'examination_regulations'; + public const MODULE_HANDBOOK = 'module_handbook'; + public const URL = 'url'; + public const DEPARTMENT = 'department'; + public const STUDENT_ADVICE = 'student_advice'; + public const SUBJECT_SPECIFIC_ADVICE = 'subject_specific_advice'; + public const SERVICE_CENTERS = 'service_centers'; + public const INFO_BROCHURE = 'info_brochure'; + public const SEMESTER_FEE = 'semester_fee'; + public const DEGREE_PROGRAM_FEES = 'degree_program_fees'; + public const ABROAD_OPPORTUNITIES = 'abroad_opportunities'; + public const KEYWORDS = 'keywords'; + public const AREA_OF_STUDY = 'area_of_study'; + public const ENTRY_TEXT = 'entry_text'; + public const COMBINATIONS = 'combinations'; + public const LIMITED_COMBINATIONS = 'limited_combinations'; + public const COMBINATIONS_CHANGESET = 'combinations_changeset'; + public const LIMITED_COMBINATIONS_CHANGESET = 'limited_combinations_changeset'; + public const NOTES_FOR_INTERNATIONAL_APPLICANTS = 'notes_for_international_applicants'; + public const STUDENT_INITIATIVES = 'student_initiatives'; + public const APPLY_NOW_LINK = 'apply_now_link'; + public const CAMPO_KEYS = 'campo_keys'; + + private IntegersListChangeset $combinationsChangeset; + private IntegersListChangeset $limitedCombinationsChangeset; + /** @var array */ + private array $events = []; + + public function __construct( + private DegreeProgramId $id, + private MultilingualString $slug, + //--- At a glance (“Auf einen Blick”) ---// + private Image $featuredImage, + private Image $teaserImage, + private MultilingualString $title, + private MultilingualString $subtitle, + /** + * Duration of studies in semester + * Regelstudienzeit + */ + private string $standardDuration, + /** + * @var MultilingualList $start One or several semesters + * Example: Summer Term, Winter Term + * Studienbeginn + */ + private MultilingualList $start, + /** + * Example: <50, 50 - 150 + * Studierendenzahl + */ + private NumberOfStudents $numberOfStudents, + /** + * Unterrichtssprache + */ + private MultilingualString $teachingLanguage, + /** + * Attribute + */ + private MultilingualList $attributes, + /** + * Abschlüsse + */ + private Degree $degree, + /** + * Fakultät + */ + private MultilingualLinks $faculty, + /** + * Studienort + */ + private MultilingualList $location, + /** + * Fächergruppen + */ + private MultilingualList $subjectGroups, + private ArrayOfStrings $videos, + private MultilingualString $metaDescription, + /** + * Schlagworte + */ + private MultilingualList $keywords, + /** + * Studienbereich + */ + private MultilingualLinks $areaOfStudy, + /** + * Einstiegtext (werbend) + */ + private MultilingualString $entryText, + //--- Content (“Inhalte”) ---// + private Content $content, + //--- Admission requirements, application and enrollment (“Zugangsvoraussetzungen, Bewerbung und Einschreibung”) ---// + /** + * Bachelor's/teaching degrees, teaching degree at a higher semester, Master’s degree + */ + private AdmissionRequirements $admissionRequirements, + /** + * Inhaltliche Zugangsvoraussetzungen Master + */ + private MultilingualString $contentRelatedMasterRequirements, + /** + * Bewerbungsfrist Wintersemester + */ + private string $applicationDeadlineWinterSemester, + /** + * Bewerbungsfrist Sommersemester + */ + private string $applicationDeadlineSummerSemester, + /** + * Details und Anmerkungen + */ + private MultilingualString $detailsAndNotes, + /** + * Sprachkenntnisse + */ + private MultilingualString $languageSkills, + /** + * “Sprachkenntnisse nur für die Philosophische Fakultät und Fachbereich Theologie + */ + private string $languageSkillsHumanitiesFaculty, + /** + * Sprachnachweise/Deutschkenntnisse für internationale Bewerberinnen und Bewerber + */ + private MultilingualLink $germanLanguageSkillsForInternationalStudents, + //--- Organization (organizational notes/links) (“Organisation (Organisatorische Hinweise/Links)”) --- // + /** + * Semesterstart + * Shared property + */ + private MultilingualLink $startOfSemester, + /** + * Semestertermine + * Shared property + */ + private MultilingualLink $semesterDates, + /** + * Prüfungsamt + */ + private MultilingualLink $examinationsOffice, + /** + * Studien- und Prüfungsordnung + */ + private string $examinationRegulations, + /** + * Modulhandbuch + */ + private string $moduleHandbook, + /** + * Studiengang-URL + */ + private MultilingualString $url, + /** + * Department/Institut (URL) + */ + private MultilingualString $department, + /** + * Allgemeine Studienberatung + * Shared property + */ + private MultilingualLink $studentAdvice, + /** + * Beratung aus dem Fach + */ + private MultilingualLink $subjectSpecificAdvice, + /** + * Beratungs- und Servicestellen der FAU + * Shared property + */ + private MultilingualLink $serviceCenters, + /** + * Infobroschüre Studiengang + */ + private string $infoBrochure, + /** + * Semesterbeitrag + * Shared property + */ + private MultilingualLink $semesterFee, + /** + * Kostenpflichtig + */ + private bool $feeRequired, + /** + * Studiengangsgebühren + */ + private MultilingualString $degreeProgramFees, + /** + * Wege ins Ausland + * Shared property + */ + private MultilingualLink $abroadOpportunities, + /** + * Hinweise für internationale Bewerber + * Shared property + */ + private MultilingualLink $notesForInternationalApplicants, + /** + * StuVe/FSI + * Shared property + */ + private MultilingualLink $studentInitiatives, + /** + * Bewerben + */ + private MultilingualLink $applyNowLink, + //--- Degree program combinations --- // + /** + * Kombinationsmöglichkeiten + */ + private DegreeProgramIds $combinations, + /** + * Eingeschränkt Kombinationsmöglichkeiten + */ + private DegreeProgramIds $limitedCombinations, + /** + * CampoKeys + */ + private CampoKeys $campoKeys, + ) { + + $this->combinationsChangeset = IntegersListChangeset::new( + $this->combinations->asArray(), + ); + + $this->limitedCombinationsChangeset = IntegersListChangeset::new( + $this->limitedCombinations->asArray(), + ); + } + + /** + * @psalm-param DegreeProgramArrayType $data + */ + public function updateDraft( + array $data, + DegreeProgramDataValidator $dataValidator, + DegreeProgramSanitizer $contentSanitizer, + ): void { + + $violations = $dataValidator->validateDraft($data); + if ($violations->count() > 0) { + throw new InvalidArgumentException('Invalid draft degree program data.'); + } + + $data = $this->sanitize($data, $contentSanitizer); + + $this->update($data); + } + + /** + * @psalm-param DegreeProgramArrayType $data + */ + public function publish( + array $data, + DegreeProgramDataValidator $dataValidator, + DegreeProgramSanitizer $contentSanitizer, + ): void { + + $violations = $dataValidator->validatePublish($data); + if ($violations->count() > 0) { + throw new InvalidArgumentException('Invalid publish degree program data.'); + } + + $data = $this->sanitize($data, $contentSanitizer); + + $this->update($data); + } + + /** + * @psalm-param DegreeProgramArrayType $data + * @psalm-return DegreeProgramArrayType $data + */ + private function sanitize(array $data, DegreeProgramSanitizer $contentSanitizer): array + { + $data[self::CONTENT] = Content::mapDescriptions( + $data[self::CONTENT], + [$contentSanitizer, 'sanitizeContentField'] + ); + foreach ( + [ + self::CONTENT_RELATED_MASTER_REQUIREMENTS, + self::DETAILS_AND_NOTES, + self::LANGUAGE_SKILLS, + self::ENTRY_TEXT, + ] as $key + ) { + $data[$key] = MultilingualString::mapTranslations( + $data[$key], + [$contentSanitizer, 'sanitizeContentField'] + ); + } + $data[self::LANGUAGE_SKILLS_HUMANITIES_FACULTY] = $contentSanitizer + ->sanitizeContentField($data[self::LANGUAGE_SKILLS_HUMANITIES_FACULTY]); + + return $data; + } + + /** + * @psalm-param DegreeProgramArrayType $data + * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + private function update(array $data): void + { + if ($data[self::ID] !== $this->id->asInt()) { + throw new RuntimeException('Invalid entity id.'); + } + + $this->slug = MultilingualString::fromArray($data[self::SLUG]); + $this->featuredImage = Image::fromArray($data[self::FEATURED_IMAGE]); + $this->teaserImage = Image::fromArray($data[self::TEASER_IMAGE]); + $this->title = MultilingualString::fromArray($data[self::TITLE]); + $this->subtitle = MultilingualString::fromArray($data[self::SUBTITLE]); + $this->standardDuration = $data[self::STANDARD_DURATION]; + $this->feeRequired = $data[self::FEE_REQUIRED]; + $this->start = MultilingualList::fromArray($data[self::START]); + $this->numberOfStudents = NumberOfStudents::fromArray($data[self::NUMBER_OF_STUDENTS]); + $this->teachingLanguage = MultilingualString::fromArray($data[self::TEACHING_LANGUAGE]); + $this->attributes = MultilingualList::fromArray($data[self::ATTRIBUTES]); + $this->degree = Degree::fromArray($data[self::DEGREE]); + $this->faculty = MultilingualLinks::fromArray($data[self::FACULTY]); + $this->location = MultilingualList::fromArray($data[self::LOCATION]); + $this->subjectGroups = MultilingualList::fromArray($data[self::SUBJECT_GROUPS]); + $this->videos = ArrayOfStrings::new(...$data[self::VIDEOS]); + $this->metaDescription = MultilingualString::fromArray($data[self::META_DESCRIPTION]); + $this->content = Content::fromArray($data[self::CONTENT]); + $this->admissionRequirements = AdmissionRequirements::fromArray($data[self::ADMISSION_REQUIREMENTS]); + $this->contentRelatedMasterRequirements = MultilingualString::fromArray($data[self::CONTENT_RELATED_MASTER_REQUIREMENTS]); + $this->applicationDeadlineWinterSemester = $data[self::APPLICATION_DEADLINE_WINTER_SEMESTER]; + $this->applicationDeadlineSummerSemester = $data[self::APPLICATION_DEADLINE_SUMMER_SEMESTER]; + $this->detailsAndNotes = MultilingualString::fromArray($data[self::DETAILS_AND_NOTES]); + $this->languageSkills = MultilingualString::fromArray($data[self::LANGUAGE_SKILLS]); + $this->languageSkillsHumanitiesFaculty = $data[self::LANGUAGE_SKILLS_HUMANITIES_FACULTY]; + $this->germanLanguageSkillsForInternationalStudents = MultilingualLink::fromArray($data[self::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS]); + $this->startOfSemester = MultilingualLink::fromArray($data[self::START_OF_SEMESTER]); + $this->semesterDates = MultilingualLink::fromArray($data[self::SEMESTER_DATES]); + $this->examinationsOffice = MultilingualLink::fromArray($data[self::EXAMINATIONS_OFFICE]); + $this->examinationRegulations = $data[self::EXAMINATION_REGULATIONS]; + $this->moduleHandbook = $data[self::MODULE_HANDBOOK]; + $this->url = MultilingualString::fromArray($data[self::URL]); + $this->department = MultilingualString::fromArray($data[self::DEPARTMENT]); + $this->studentAdvice = MultilingualLink::fromArray($data[self::STUDENT_ADVICE]); + $this->subjectSpecificAdvice = MultilingualLink::fromArray($data[self::SUBJECT_SPECIFIC_ADVICE]); + $this->serviceCenters = MultilingualLink::fromArray($data[self::SERVICE_CENTERS]); + $this->infoBrochure = $data[self::INFO_BROCHURE]; + $this->semesterFee = MultilingualLink::fromArray($data[self::SEMESTER_FEE]); + $this->degreeProgramFees = MultilingualString::fromArray($data[self::DEGREE_PROGRAM_FEES]); + $this->abroadOpportunities = MultilingualLink::fromArray($data[self::ABROAD_OPPORTUNITIES]); + $this->keywords = MultilingualList::fromArray($data[self::KEYWORDS]); + $this->areaOfStudy = MultilingualLinks::fromArray($data[self::AREA_OF_STUDY]); + $this->combinations = DegreeProgramIds::fromArray($data[self::COMBINATIONS]); + $this->limitedCombinations = DegreeProgramIds::fromArray($data[self::LIMITED_COMBINATIONS]); + $this->notesForInternationalApplicants = MultilingualLink::fromArray($data[self::NOTES_FOR_INTERNATIONAL_APPLICANTS]); + $this->studentInitiatives = MultilingualLink::fromArray($data[self::STUDENT_INITIATIVES]); + $this->applyNowLink = MultilingualLink::fromArray($data[self::APPLY_NOW_LINK]); + $this->entryText = MultilingualString::fromArray($data[self::ENTRY_TEXT]); + $this->campoKeys = CampoKeys::fromArray($data[self::CAMPO_KEYS]); + + $this->combinationsChangeset = $this + ->combinationsChangeset + ->applyChanges($data[self::COMBINATIONS]); + $this->limitedCombinationsChangeset = $this + ->limitedCombinationsChangeset + ->applyChanges($data[self::LIMITED_COMBINATIONS]); + + $this->events[] = DegreeProgramUpdated::new($this->id->asInt()); + } + + /** + * @return array{ + * id: DegreeProgramId, + * slug: MultilingualString, + * featured_image: Image, + * teaser_image: Image, + * title: MultilingualString, + * subtitle: MultilingualString, + * standard_duration: string, + * fee_required: bool, + * start: MultilingualList, + * number_of_students: NumberOfStudents, + * teaching_language: MultilingualString, + * attributes: MultilingualList, + * degree: Degree, + * faculty: MultilingualLinks, + * location: MultilingualList, + * subject_groups: MultilingualList, + * videos: ArrayOfStrings, + * meta_description: MultilingualString, + * content: Content, + * admission_requirements: AdmissionRequirements, + * content_related_master_requirements: MultilingualString, + * application_deadline_winter_semester: string, + * application_deadline_summer_semester: string, + * details_and_notes: MultilingualString, + * language_skills: MultilingualString, + * language_skills_humanities_faculty: string, + * german_language_skills_for_international_students: MultilingualLink, + * start_of_semester: MultilingualLink, + * semester_dates: MultilingualLink, + * examinations_office: MultilingualLink, + * examination_regulations: string, + * module_handbook: string, + * url: MultilingualString, + * department: MultilingualString, + * student_advice: MultilingualLink, + * subject_specific_advice: MultilingualLink, + * service_centers: MultilingualLink, + * info_brochure: string, + * semester_fee: MultilingualLink, + * degree_program_fees: MultilingualString, + * abroad_opportunities: MultilingualLink, + * keywords: MultilingualList, + * area_of_study: MultilingualLinks, + * combinations: DegreeProgramIds, + * limited_combinations: DegreeProgramIds, + * combinations_changeset: IntegersListChangeset, + * limited_combinations_changeset: IntegersListChangeset, + * notes_for_international_applicants: MultilingualLink, + * student_initiatives: MultilingualLink, + * apply_now_link: MultilingualLink, + * entry_text: MultilingualString, + * campo_keys: CampoKeys, + * } + * @internal Only for repositories usage + * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + public function asArray(): array + { + return [ + self::ID => $this->id, + self::SLUG => $this->slug, + self::FEATURED_IMAGE => $this->featuredImage, + self::TEASER_IMAGE => $this->teaserImage, + self::TITLE => $this->title, + self::SUBTITLE => $this->subtitle, + self::STANDARD_DURATION => $this->standardDuration, + self::FEE_REQUIRED => $this->feeRequired, + self::START => $this->start, + self::NUMBER_OF_STUDENTS => $this->numberOfStudents, + self::TEACHING_LANGUAGE => $this->teachingLanguage, + self::ATTRIBUTES => $this->attributes, + self::DEGREE => $this->degree, + self::FACULTY => $this->faculty, + self::LOCATION => $this->location, + self::SUBJECT_GROUPS => $this->subjectGroups, + self::VIDEOS => $this->videos, + self::META_DESCRIPTION => $this->metaDescription, + self::CONTENT => $this->content, + self::ADMISSION_REQUIREMENTS => $this->admissionRequirements, + self::CONTENT_RELATED_MASTER_REQUIREMENTS => $this->contentRelatedMasterRequirements, + self::APPLICATION_DEADLINE_WINTER_SEMESTER => $this->applicationDeadlineWinterSemester, + self::APPLICATION_DEADLINE_SUMMER_SEMESTER => $this->applicationDeadlineSummerSemester, + self::DETAILS_AND_NOTES => $this->detailsAndNotes, + self::LANGUAGE_SKILLS => $this->languageSkills, + self::LANGUAGE_SKILLS_HUMANITIES_FACULTY => $this->languageSkillsHumanitiesFaculty, + self::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS => + $this->germanLanguageSkillsForInternationalStudents, + self::START_OF_SEMESTER => $this->startOfSemester, + self::SEMESTER_DATES => $this->semesterDates, + self::EXAMINATIONS_OFFICE => $this->examinationsOffice, + self::EXAMINATION_REGULATIONS => $this->examinationRegulations, + self::MODULE_HANDBOOK => $this->moduleHandbook, + self::URL => $this->url, + self::DEPARTMENT => $this->department, + self::STUDENT_ADVICE => $this->studentAdvice, + self::SUBJECT_SPECIFIC_ADVICE => $this->subjectSpecificAdvice, + self::SERVICE_CENTERS => $this->serviceCenters, + self::INFO_BROCHURE => $this->infoBrochure, + self::SEMESTER_FEE => $this->semesterFee, + self::DEGREE_PROGRAM_FEES => $this->degreeProgramFees, + self::ABROAD_OPPORTUNITIES => $this->abroadOpportunities, + self::KEYWORDS => $this->keywords, + self::AREA_OF_STUDY => $this->areaOfStudy, + self::COMBINATIONS => $this->combinations, + self::LIMITED_COMBINATIONS => $this->limitedCombinations, + self::COMBINATIONS_CHANGESET => $this->combinationsChangeset, + self::LIMITED_COMBINATIONS_CHANGESET => $this->limitedCombinationsChangeset, + self::NOTES_FOR_INTERNATIONAL_APPLICANTS => $this->notesForInternationalApplicants, + self::STUDENT_INITIATIVES => $this->studentInitiatives, + self::APPLY_NOW_LINK => $this->applyNowLink, + self::ENTRY_TEXT => $this->entryText, + self::CAMPO_KEYS => $this->campoKeys, + ]; + } + + /** + * @return array + */ + public function releaseEvents(): array + { + return $this->events; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramDataValidator.php b/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramDataValidator.php new file mode 100644 index 000000000..ecfa9a35c --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramDataValidator.php @@ -0,0 +1,20 @@ + $data + * @return Violations Violations array + */ + public function validatePublish(array $data): Violations; + + /** + * @param array $data + * @return Violations Violations array + */ + public function validateDraft(array $data): Violations; +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramId.php b/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramId.php new file mode 100644 index 000000000..942da44d3 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramId.php @@ -0,0 +1,33 @@ +id); + } + + public static function fromInt(int $id): self + { + return new self($id); + } + + public function asInt(): int + { + return $this->id; + } + + public function jsonSerialize(): int + { + return $this->asInt(); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramIds.php b/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramIds.php new file mode 100644 index 000000000..6ae16606f --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramIds.php @@ -0,0 +1,50 @@ + + */ +final class DegreeProgramIds extends ArrayObject implements JsonSerializable +{ + private function __construct(DegreeProgramId ...$ids) + { + parent::__construct($ids); + } + + public static function new(DegreeProgramId ...$ids): self + { + return new self(...$ids); + } + + /** + * @param array $ids + */ + public static function fromArray(array $ids): self + { + return new self( + ...array_map([DegreeProgramId::class, 'fromInt'], $ids) + ); + } + + /** + * @return array + */ + public function asArray(): array + { + return array_map( + static fn(DegreeProgramId $degreeProgramId) => $degreeProgramId->asInt(), + $this->getArrayCopy() + ); + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramRepository.php b/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramRepository.php new file mode 100644 index 000000000..81ec22c41 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/DegreeProgramRepository.php @@ -0,0 +1,20 @@ + [ + 'title' => [], + 'src' => [], + 'alt' => [], + 'srcset' => [], + 'sizes' => [], + ], + 'picture' => [ + 'title' => [], + 'src' => [], + 'alt' => [], + ], + 'figure' => [ + 'title' => [], + 'src' => [], + 'alt' => [], + ], + 'a' => [ + 'title' => [], + 'href' => [], + 'target' => [], + ], + 'blockquote' => [ + 'class' => [], + ], + 'cite' => [], + 'br' => [], + 'p' => [], + 'strong' => [], + 'ul' => [], + 'ol' => [], + 'li' => [], + 'dl' => [], + 'dd' => [], + 'dt' => [], + 'h3' => [], + 'h4' => [], + 'h5' => [], + ]; + + public const ALLOWED_SHORTCODES = [ + 'alert', + 'contact', + 'fau-video', + ]; + + public const ALLOWED_BLOCKS = [ + 'core/heading', + 'core/image', + 'core/list', + 'core/paragraph', + 'core/shortcode', + 'core/quote', + 'fau/description-list', + ]; + + public function sanitizeContentField(string $content): string; +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/Event/DegreeProgramUpdated.php b/vendor/rrze/fau-studium-common/src/Domain/Event/DegreeProgramUpdated.php new file mode 100644 index 000000000..04dc0f04d --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/Event/DegreeProgramUpdated.php @@ -0,0 +1,31 @@ +id; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/Image.php b/vendor/rrze/fau-studium-common/src/Domain/Image.php new file mode 100644 index 000000000..864572908 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/Image.php @@ -0,0 +1,102 @@ + 'object', + 'additionalProperties' => false, + 'required' => [Image::ID, Image::URL], + 'properties' => [ + Image::ID => [ + 'type' => 'integer', + 'minimum' => 0, + ], + Image::URL => [ + 'type' => 'string', + ], + ], + ]; + + public const SCHEMA_REQUIRED = [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => [Image::ID, Image::URL], + 'properties' => [ + Image::ID => [ + 'type' => 'integer', + 'minimum' => 1, + ], + Image::URL => [ + 'type' => 'string', + ], + ], + ]; + + private function __construct( + private int $id, + private string $url, + ) { + + $id >= 0 or throw new InvalidArgumentException(); + } + + public static function empty(): self + { + return new self(0, ''); + } + + public static function new(int $id, string $url): self + { + return new self( + $id, + $url, + ); + } + + /** + * @psalm-param array{id: int, url: string} $data + */ + public static function fromArray(array $data): self + { + return new self( + $data[self::ID], + $data[self::URL], + ); + } + + /** + * @return array{id: int, url: string} + */ + public function asArray(): array + { + return [ + self::ID => $this->id, + self::URL => $this->url, + ]; + } + + public function id(): int + { + return $this->id; + } + + public function url(): string + { + return $this->url; + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/MultilingualLink.php b/vendor/rrze/fau-studium-common/src/Domain/MultilingualLink.php new file mode 100644 index 000000000..32e9aadb8 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/MultilingualLink.php @@ -0,0 +1,135 @@ + 'object', + 'additionalProperties' => false, + 'required' => [ + MultilingualLink::ID, + MultilingualLink::NAME, + MultilingualLink::LINK_TEXT, + MultilingualLink::LINK_URL, + ], + 'properties' => [ + MultilingualLink::ID => [ + 'type' => 'string', + ], + MultilingualLink::NAME => MultilingualString::SCHEMA, + MultilingualLink::LINK_TEXT => MultilingualString::SCHEMA, + MultilingualLink::LINK_URL => MultilingualString::SCHEMA, + ], + ]; + + public const SCHEMA_REQUIRED = [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => [ + MultilingualLink::ID, + MultilingualLink::NAME, + MultilingualLink::LINK_TEXT, + MultilingualLink::LINK_URL, + ], + 'properties' => [ + MultilingualLink::ID => [ + 'type' => 'string', + 'minLength' => 1, + ], + MultilingualLink::NAME => MultilingualString::SCHEMA, + MultilingualLink::LINK_TEXT => MultilingualString::SCHEMA, + MultilingualLink::LINK_URL => MultilingualString::SCHEMA, + ], + ]; + + private function __construct( + private string $id, + private MultilingualString $name, + private MultilingualString $linkText, + private MultilingualString $linkUrl, + ) { + } + + public static function new( + string $id, + MultilingualString $name, + MultilingualString $linkText, + MultilingualString $linkUrl, + ): self { + + return new self($id, $name, $linkText, $linkUrl); + } + + public static function empty(): self + { + return new self( + '', + MultilingualString::empty(), + MultilingualString::empty(), + MultilingualString::empty(), + ); + } + + /** + * @psalm-param MultilingualLinkType $data + */ + public static function fromArray(array $data): self + { + return new self( + $data[self::ID], + MultilingualString::fromArray($data[self::NAME]), + MultilingualString::fromArray($data[self::LINK_TEXT]), + MultilingualString::fromArray($data[self::LINK_URL]), + ); + } + + /** + * @return MultilingualLinkType + */ + public function asArray(): array + { + return [ + self::ID => $this->id, + self::NAME => $this->name->asArray(), + self::LINK_TEXT => $this->linkText->asArray(), + self::LINK_URL => $this->linkUrl->asArray(), + ]; + } + + public function id(): string + { + return $this->id; + } + + public function name(): MultilingualString + { + return $this->name; + } + + public function linkText(): MultilingualString + { + return $this->linkText; + } + + public function linkUrl(): MultilingualString + { + return $this->linkUrl; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/MultilingualLinks.php b/vendor/rrze/fau-studium-common/src/Domain/MultilingualLinks.php new file mode 100644 index 000000000..947f6f355 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/MultilingualLinks.php @@ -0,0 +1,62 @@ + + * @psalm-import-type MultilingualLinkType from MultilingualLink + */ +final class MultilingualLinks extends ArrayObject implements JsonSerializable +{ + public const SCHEMA = [ + 'type' => 'array', + 'items' => MultilingualLink::SCHEMA, + ]; + + public const SCHEMA_REQUIRED = [ + 'type' => 'array', + 'items' => MultilingualLink::SCHEMA_REQUIRED, + 'minItems' => 1, + ]; + + private function __construct(MultilingualLink ...$multilingualLinks) + { + parent::__construct($multilingualLinks); + } + + public static function new(MultilingualLink ...$multilingualLinks): self + { + return new self(...$multilingualLinks); + } + + /** + * @param array $items + */ + public static function fromArray(array $items): self + { + return new self( + ...array_map([MultilingualLink::class, 'fromArray'], $items) + ); + } + + /** + * @return array + */ + public function asArray(): array + { + return array_map( + static fn(MultilingualLink $multilingualLink) => $multilingualLink->asArray(), + $this->getArrayCopy() + ); + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/MultilingualList.php b/vendor/rrze/fau-studium-common/src/Domain/MultilingualList.php new file mode 100644 index 000000000..fa7571d82 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/MultilingualList.php @@ -0,0 +1,84 @@ + + * @psalm-import-type MultilingualStringType from MultilingualString + */ +final class MultilingualList extends ArrayObject implements \JsonSerializable +{ + public const SCHEMA = [ + 'type' => 'array', + 'items' => MultilingualString::SCHEMA, + ]; + + public const SCHEMA_REQUIRED = [ + 'type' => 'array', + 'items' => MultilingualString::SCHEMA, + 'minItems' => 1, + ]; + + private function __construct(MultilingualString ...$strings) + { + parent::__construct($strings); + } + + public static function new(MultilingualString ...$strings): self + { + return new self(...$strings); + } + + /** + * @param array $items + */ + public static function fromArray(array $items): self + { + $multilingualStrings = []; + foreach ($items as $item) { + $multilingualStrings[] = MultilingualString::fromArray($item); + } + + return new self(...$multilingualStrings); + } + + /** + * @return array + */ + public function asArray(): array + { + return array_map( + static fn(MultilingualString $multilingualString) => $multilingualString->asArray(), + $this->getArrayCopy() + ); + } + + public function asArrayOfStrings(string $languageCode): ArrayOfStrings + { + return ArrayOfStrings::new( + ...array_map( + static fn(MultilingualString $multilingualString): string => $multilingualString->asString($languageCode), + $this->getArrayCopy() + ) + ); + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } + + public function containGermanString(string $string): bool + { + return in_array( + $string, + $this->asArrayOfStrings(MultilingualString::DE)->getArrayCopy(), + true + ); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/MultilingualString.php b/vendor/rrze/fau-studium-common/src/Domain/MultilingualString.php new file mode 100644 index 000000000..31bcbfb17 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/MultilingualString.php @@ -0,0 +1,196 @@ + 'object', + 'additionalProperties' => false, + 'required' => ['id', MultilingualString::DE, MultilingualString::EN], + 'properties' => [ + 'id' => [ + 'type' => 'string', + ], + MultilingualString::DE => [ + 'type' => 'string', + ], + MultilingualString::EN => [ + 'type' => 'string', + ], + ], + ]; + + public const SCHEMA_REQUIRED = [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => ['id', MultilingualString::DE, MultilingualString::EN], + 'properties' => [ + 'id' => [ + 'type' => 'string', + ], + MultilingualString::DE => [ + 'type' => 'string', + 'minLength' => 1, + ], + MultilingualString::EN => [ + 'type' => 'string', + 'minLength' => 1, + ], + ], + ]; + + public const SCHEMA_URL_REQUIRED = [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => ['id', MultilingualString::DE, MultilingualString::EN], + 'properties' => [ + 'id' => [ + 'type' => 'string', + ], + MultilingualString::DE => [ + 'type' => 'string', + 'minLength' => 1, + 'format' => 'uri', + ], + MultilingualString::EN => [ + 'type' => 'string', + 'minLength' => 1, + 'format' => 'uri', + ], + ], + ]; + + public const SCHEMA_ID_REQUIRED = [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => ['id', MultilingualString::DE, MultilingualString::EN], + 'properties' => [ + 'id' => [ + 'type' => 'string', + 'minLength' => 1, + ], + MultilingualString::DE => [ + 'type' => 'string', + ], + MultilingualString::EN => [ + 'type' => 'string', + ], + ], + ]; + + public const LANGUAGES = [ + self::DE => 'Deutsch', + self::EN => 'English', + ]; + + /** @var array{de: string, en: string} */ + private array $translations; + + private function __construct( + private string $id, + string $de, + string $en, + ) { + + $this->translations = [ + self::DE => $de, + self::EN => $en, + ]; + } + + public static function empty(): self + { + return new self('', '', ''); + } + + public static function fromTranslations(string $id, string $de, string $en): self + { + return new self($id, $de, $en); + } + + /** + * @psalm-param MultilingualStringType $translations + */ + public static function fromArray(array $translations): self + { + return new self( + $translations['id'], + $translations[self::DE], + $translations[self::EN], + ); + } + + /** + * @return MultilingualStringType + */ + public function asArray(): array + { + return array_merge( + ['id' => $this->id], + $this->translations + ); + } + + /** + * @psalm-param MultilingualStringType $data + * @psalm-param callable(string): string $callback + * @psalm-return MultilingualStringType + */ + public static function mapTranslations(array $data, callable $callback): array + { + $data[self::DE] = $callback($data[self::DE]); + $data[self::EN] = $callback($data[self::EN]); + + return $data; + } + + public function asString(string $languageCode): string + { + if ($languageCode) { + return $this->translations[$languageCode] ?? ''; + } + + return $this->translations[self::DE] ?: $this->translations[self::EN]; + } + + public function id(): string + { + return $this->id; + } + + public function inGerman(): string + { + return $this->translations[self::DE] ?? ''; + } + + public function inEnglish(): string + { + return $this->translations[self::EN] ?? ''; + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } + + public function mergeWithDefault(MultilingualString $multilingualString): self + { + return new self( + $this->id ?: $multilingualString->id, + $this->translations[self::DE] ?: $multilingualString->translations[self::DE], + $this->translations[self::EN] ?: $multilingualString->translations[self::EN], + ); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/NumberOfStudents.php b/vendor/rrze/fau-studium-common/src/Domain/NumberOfStudents.php new file mode 100644 index 000000000..895388bd3 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/NumberOfStudents.php @@ -0,0 +1,128 @@ + 'object', + 'additionalProperties' => false, + 'required' => [ + NumberOfStudents::ID, + NumberOfStudents::NAME, + NumberOfStudents::DESCRIPTION, + ], + 'properties' => [ + NumberOfStudents::ID => [ + 'type' => 'string', + ], + NumberOfStudents::NAME => [ + 'type' => 'string', + ], + NumberOfStudents::DESCRIPTION => [ + 'type' => 'string', + ], + ], + ]; + + public const SCHEMA_REQUIRED = [ + 'type' => 'object', + 'additionalProperties' => false, + 'required' => [ + NumberOfStudents::ID, + NumberOfStudents::NAME, + NumberOfStudents::DESCRIPTION, + ], + 'properties' => [ + NumberOfStudents::ID => [ + 'type' => 'string', + 'minLength' => 1, + ], + NumberOfStudents::NAME => [ + 'type' => 'string', + ], + NumberOfStudents::DESCRIPTION => [ + 'type' => 'string', + ], + ], + ]; + + private function __construct( + private string $id, + private string $name, + private string $description, + ) { + } + + public static function empty(): self + { + return new self('', '', ''); + } + + public static function new(string $id, string $name, string $description): self + { + return new self( + $id, + $name, + $description, + ); + } + + /** + * @psalm-param NumberOfStudentsType $data + */ + public static function fromArray(array $data): self + { + return new self( + $data[self::ID], + $data[self::NAME], + $data[self::DESCRIPTION], + ); + } + + public function id(): string + { + return $this->id; + } + + public function name(): string + { + return $this->name; + } + + public function description(): string + { + return $this->description; + } + + /** + * @return NumberOfStudentsType + */ + public function asArray(): array + { + return [ + self::ID => $this->id, + self::NAME => $this->name, + self::DESCRIPTION => $this->description, + ]; + } + + public function asString(): string + { + return $this->name; + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/Violation.php b/vendor/rrze/fau-studium-common/src/Domain/Violation.php new file mode 100644 index 000000000..cdbef04e5 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/Violation.php @@ -0,0 +1,72 @@ + $this->path(), + 'errorMessage' => $this->errorMessage(), + 'errorCode' => $this->errorCode(), + ]; + } + + public function jsonSerialize(): array + { + return $this->asArray(); + } + + public function path(): string + { + return $this->path; + } + + public function readablePath(): string + { + $result = str_replace('.id', '', $this->path); + $result = ucwords($result, '.'); + return str_replace(['_', '.'], [' ', ' - '], $result); + } + + public function errorMessage(): string + { + return $this->errorMessage; + } + + public function errorCode(): string + { + return $this->errorCode; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Domain/Violations.php b/vendor/rrze/fau-studium-common/src/Domain/Violations.php new file mode 100644 index 000000000..aff83fa37 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Domain/Violations.php @@ -0,0 +1,62 @@ + + * @psalm-import-type ViolationType from Violation + */ +final class Violations extends ArrayObject implements JsonSerializable +{ + private function __construct(Violation ...$violations) + { + $result = []; + + foreach ($violations as $violation) { + $result[$violation->path()] = $violation; + } + + parent::__construct($result); + } + + public static function new(Violation ...$violations): self + { + return new self(...$violations); + } + + /** + * Undocumented function + * + * @return array + */ + public function asArray(): array + { + return array_map( + static fn(Violation $violation) => $violation->asArray(), + $this->getArrayCopy() + ); + } + + public function jsonSerialize(): array + { + return $this->getArrayCopy(); + } + + public function append(mixed $value): void + { + throw new BadMethodCallException("Invalid append call"); + } + + public function add(Violation ...$violations): void + { + foreach ($violations as $violation) { + $this->offsetSet($violation->path(), $violation); + } + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Cache/PostMetaDegreeProgramCache.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Cache/PostMetaDegreeProgramCache.php new file mode 100644 index 000000000..c900a89ce --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Cache/PostMetaDegreeProgramCache.php @@ -0,0 +1,148 @@ +cacheKeyGenerator->parseForDegreeProgram($key); + + $meta = get_post_meta($postId, self::postMetaKey($type), true); + if (!$meta) { + return null; + } + + try { + return (array) json_decode((string) $meta, true, 512, JSON_THROW_ON_ERROR); + } catch (JsonException) { + return null; + } + } + + public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool + { + [$type, $postId] = $this->cacheKeyGenerator->parseForDegreeProgram($key); + $metaKey = self::postMetaKey($type); + + try { + // `update_metadata` returns false if value was not changed. + // We need to handle this edge case separately. + $encodedValue = json_encode($value, JSON_THROW_ON_ERROR); + $existedValue = get_post_meta($postId, $metaKey, true); + if ($encodedValue === $existedValue) { + return true; + } + + // Add slashes to prevent broken JSON encoded value + // because `update_metadata` uses wp_unslash under the hood. + // `update_metadata` is used to allow adding post meta to revisions. + return (bool) update_metadata('post', $postId, $metaKey, addslashes($encodedValue)); + } catch (JsonException) { + return false; + } + } + + public function delete(string $key): bool + { + if (!$this->has($key)) { + // To prevent wrong result if meta doesn't exist + return true; + } + + [$type, $postId] = $this->cacheKeyGenerator->parseForDegreeProgram($key); + + return delete_post_meta($postId, self::postMetaKey($type)); + } + + public function clear(): bool + { + /** @var array $ids */ + $ids = get_posts([ + 'numberposts' => -1, + 'post_type' => DegreeProgramPostType::KEY, + 'post_status' => 'any', + 'meta_query' => [ + 'relation' => 'OR', + [ + 'key' => self::postMetaKey(CacheKeyGenerator::RAW_TYPE), + 'compare' => 'EXISTS', + ], + [ + 'key' => self::postMetaKey(CacheKeyGenerator::TRANSLATED_TYPE), + 'compare' => 'EXISTS', + ], + ], + 'fields' => 'ids', + ]); + + $result = []; + foreach ($ids as $id) { + $result[] = delete_post_meta( + $id, + self::postMetaKey(CacheKeyGenerator::RAW_TYPE) + ); + $result[] = delete_post_meta( + $id, + self::postMetaKey(CacheKeyGenerator::TRANSLATED_TYPE) + ); + } + + return !in_array(false, $result, true); + } + + public function getMultiple(iterable $keys, mixed $default = null): iterable + { + $result = []; + foreach ($keys as $key) { + $result[$key] = $this->get($key); + } + + return $result; + } + + public function setMultiple(iterable $values, DateInterval|int|null $ttl = null): bool + { + $result = []; + foreach ($values as $key => $value) { + $result[] = $this->set((string) $key, $value); + } + + return !in_array(false, $result, true); + } + + public function deleteMultiple(iterable $keys): bool + { + $result = []; + foreach ($keys as $key) { + $result[] = $this->delete($key); + } + + return !in_array(false, $result, true); + } + + public function has(string $key): bool + { + [$type, $postId] = $this->cacheKeyGenerator->parseForDegreeProgram($key); + + return metadata_exists('post', $postId, self::postMetaKey($type)); + } + + public static function postMetaKey(string $type): string + { + return 'fau_cache_degree_program_' . $type; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Cli/DegreeProgramCacheCommand.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Cli/DegreeProgramCacheCommand.php new file mode 100644 index 000000000..3c13421d9 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Cli/DegreeProgramCacheCommand.php @@ -0,0 +1,34 @@ +cacheInvalidator->invalidateFully(); + } catch (Throwable $exception) { + WP_CLI::error($exception); + } + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Content/PostType/DegreeProgramPostType.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Content/PostType/DegreeProgramPostType.php new file mode 100644 index 000000000..95ae46df9 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Content/PostType/DegreeProgramPostType.php @@ -0,0 +1,213 @@ + _x( + 'Degree Programs', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'labels' => self::labels(), + 'hierarchical' => false, + 'supports' => [ + 'editor', + 'author', + ], + ] + ); + } + + public static function public(): self + { + return self::default()->merge( + [ + 'public' => true, + 'show_in_rest' => true, + 'rest_base' => self::REST_BASE, + 'menu_icon' => 'dashicons-welcome-learn-more', + ] + ); + } + + public static function hidden(): self + { + return self::default()->merge( + [ + 'public' => false, + 'publicly_queryable' => true, + 'show_in_rest' => false, + ] + ); + } + + /** + * @return array + * @phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + private static function labels(): array + { + return [ + 'name' => _x( + 'Degree Programs', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'singular_name' => _x( + 'Degree Program', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'add_new' => _x( + 'Add New Degree Program', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'add_new_item' => _x( + 'Add New Degree Program', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'edit_item' => _x( + 'Edit Degree Program', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'new_item' => _x( + 'New Degree Program', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'view_item' => _x( + 'View Degree Program', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'view_items' => _x( + 'View Degree Programs', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'search_items' => _x( + 'Search Degree Programs', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'not_found' => _x( + 'No degree programs found.', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'not_found_in_trash' => _x( + 'No degree programs found in Trash.', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'all_items' => _x( + 'All Degree Programs', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'archives' => _x( + 'Degree Program Archives', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'attributes' => _x( + 'Degree Program Attributes', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'insert_into_item' => _x( + 'Insert into degree program', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'uploaded_to_this_item' => _x( + 'Uploaded to this degree program', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'filter_items_list' => _x( + 'Filter degree programs list', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'items_list_navigation' => _x( + 'Degree programs list navigation', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'items_list' => _x( + 'Degree programs list', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'item_published' => _x( + 'Degree program published.', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'item_published_privately' => _x( + 'Degree program published privately.', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'item_reverted_to_draft' => _x( + 'Degree program reverted to draft.', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'item_scheduled' => _x( + 'Degree program scheduled.', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'item_updated' => _x( + 'Degree program updated.', + 'backoffice: post type label', + 'fau-degree-program-common' + ), + 'item_link' => _x( + 'Degree Program Link.', + 'backoffice: navigation link block title', + 'fau-degree-program-common' + ), + 'item_link_description' => _x( + 'A link to a degree program.', + 'backoffice: navigation link block description', + 'fau-degree-program-common' + ), + ]; + } + + public function args(): array + { + return $this->args; + } + + public function key(): string + { + return self::KEY; + } + + public function merge(array $args): self + { + return new self(array_merge($this->args, $args)); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php new file mode 100644 index 000000000..fe068163f --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/ApplyNowLinkTaxonomy.php @@ -0,0 +1,44 @@ +> + */ +final class TaxonomiesList extends ArrayObject +{ + /** + * @var array + */ + private array $restBaseSlugMap = []; + + private function __construct() + { + parent::__construct([ + ApplyNowLinkTaxonomy::class, + AreaOfStudyTaxonomy::class, + AttributeTaxonomy::class, + BachelorOrTeachingDegreeAdmissionRequirementTaxonomy::class, + DegreeTaxonomy::class, + ExaminationsOfficeTaxonomy::class, + FacultyTaxonomy::class, + GermanLanguageSkillsForInternationalStudentsTaxonomy::class, + KeywordTaxonomy::class, + MasterDegreeAdmissionRequirementTaxonomy::class, + NumberOfStudentsTaxonomy::class, + SemesterTaxonomy::class, + StudyLocationTaxonomy::class, + SubjectGroupTaxonomy::class, + SubjectSpecificAdviceTaxonomy::class, + TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy::class, + TeachingLanguageTaxonomy::class, + ]); + + foreach ($this->getArrayCopy() as $item) { + if (!defined("{$item}::KEY")) { + continue; + } + + $restBase = (string) constant("{$item}::REST_BASE"); + $key = (string) constant("{$item}::KEY"); + $this->restBaseSlugMap[$restBase] = $key; + } + } + + public static function new(): self + { + return new self(); + } + + public function keys(): ArrayOfStrings + { + return ArrayOfStrings::new(...array_values($this->restBaseSlugMap)); + } + + public function convertRestBaseToSlug(string $restBase): ?string + { + return $this->restBaseSlugMap[$restBase] ?? null; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/Taxonomy.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/Taxonomy.php new file mode 100644 index 000000000..f92502edc --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/Taxonomy.php @@ -0,0 +1,201 @@ +args = array_merge($this->args, [ + 'label' => $this->pluralName(), + 'labels' => self::labels( + plural: $this->pluralName(), + singular: $this->singularName() + ), + 'hierarchical' => $this->isHierarchical(), + 'rest_base' => $this->restBase(), + ]); + } + + private static function default(): static + { + + return new static([]); + } + + final public static function public(): static + { + return self::default()->merge( + [ + 'public' => true, + 'show_in_rest' => true, + 'meta_box_cb' => false, + ] + ); + } + + final public static function hidden(): static + { + return self::default()->merge( + [ + 'public' => false, + 'show_in_rest' => false, + ] + ); + } + + final public function args(): array + { + return $this->args; + } + + abstract public function key(): string; + abstract public function restBase(): string; + abstract protected function pluralName(): string; + abstract protected function singularName(): string; + abstract protected function isHierarchical(): bool; + + public function merge(array $args): static + { + return new static(array_merge($this->args, $args)); + } + + /** + * @phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + private static function labels(string $plural, string $singular): array + { + return [ + 'name' => $plural, + 'singular_name' => $singular, + 'search_items' => sprintf( + /* translators: %s - taxonomy plural name */ + _x('Search %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $plural + ), + 'popular_items' => sprintf( + /* translators: %s - taxonomy plural name */ + _x('Popular %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $plural + ), + 'all_items' => sprintf( + /* translators: %s - taxonomy plural name */ + _x('All %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $plural + ), + 'parent_item' => sprintf( + /* translators: %s - taxonomy singular name */ + _x('Parent %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $singular + ), + 'parent_item_colon' => sprintf( + /* translators: %s - taxonomy singular name */ + _x('Parent %s:', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $singular + ), + 'edit_item' => sprintf( + /* translators: %s - taxonomy singular name */ + _x('Edit %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $singular + ), + 'view_item' => sprintf( + /* translators: %s - taxonomy singular name */ + _x('View %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $singular + ), + 'update_item' => sprintf( + /* translators: %s - taxonomy singular name */ + _x('Update %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $singular + ), + 'add_new_item' => sprintf( + /* translators: %s - taxonomy singular name */ + _x('Add New %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $singular + ), + 'new_item_name' => sprintf( + /* translators: %s - taxonomy singular name */ + _x('New %s Name', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $singular + ), + 'separate_items_with_commas' => sprintf( + /* translators: %s - taxonomy plural name */ + _x( + 'Separate %s with commas', + 'backoffice: taxonomy label', + 'fau-degree-program-common' + ), + $plural + ), + 'add_or_remove_items' => sprintf( + /* translators: %s - taxonomy plural name */ + _x('Add or remove %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $plural + ), + 'choose_from_most_used' => sprintf( + /* translators: %s - taxonomy plural name */ + _x( + 'Choose from the most used %s', + 'backoffice: taxonomy label', + 'fau-degree-program-common' + ), + $plural + ), + 'not_found' => sprintf( + /* translators: %s - taxonomy plural name */ + _x('No %s found.', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $plural + ), + 'no_terms' => sprintf( + /* translators: %s - taxonomy plural name */ + _x('No %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $plural + ), + 'filter_by_item' => sprintf( + /* translators: %s - taxonomy singular name */ + _x('Filter by %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $singular + ), + 'items_list_navigation' => sprintf( + /* translators: %s - taxonomy plural name */ + _x( + '%s list navigation', + 'backoffice: taxonomy label', + 'fau-degree-program-common' + ), + $plural + ), + 'items_list' => sprintf( + /* translators: %s - taxonomy plural name */ + _x('%s list', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $plural + ), + 'back_to_items' => sprintf( + /* translators: %s - taxonomy plural name */ + _x('← Go to %s', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $plural + ), + 'item_link' => sprintf( + /* translators: %s - taxonomy singular name */ + _x('%s Link', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $singular + ), + 'item_link_description' => sprintf( + /* translators: %s - taxonomy singular name */ + _x('A link to a %s.', 'backoffice: taxonomy label', 'fau-degree-program-common'), + $singular + ), + ]; + } + + final public function showAdminColumn(): static + { + return $this->merge([ + 'show_admin_column' => true, + ]); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php new file mode 100644 index 000000000..c275b2bec --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Content/Taxonomy/TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy.php @@ -0,0 +1,47 @@ + $menuItems + */ + private function __construct(private array $menuItems) + { + } + + public static function new(): self + { + return new self([]); + } + + public function withMenuItem(MenuItem $item): self + { + $this->menuItems[] = $item; + return new self($this->menuItems); + } + + public function render(WP_Admin_Bar $adminBar): void + { + if (! current_user_can('delete_users')) { + return; + } + + if (count($this->menuItems) === 1) { + $menuItem = $this->menuItems[0]; + + $adminBar->add_menu( + [ + 'id' => self::PARENT_ID . '-' . $menuItem->id(), + 'title' => $menuItem->title(), + 'href' => $menuItem->href(), + ] + ); + return; + } + + $adminBar->add_menu( + [ + 'id' => self::PARENT_ID, + 'title' => _x( + 'FAU Degree Program', + 'backoffice: admin bar menu item', + 'fau-degree-program-common' + ), + 'href' => '#', + ] + ); + + foreach ($this->menuItems as $menuItem) { + $adminBar->add_menu( + [ + 'id' => self::PARENT_ID . '-' . $menuItem->id(), + 'parent' => self::PARENT_ID, + 'title' => $menuItem->title(), + 'href' => $menuItem->href(), + ] + ); + } + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/AdminPostAction.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/AdminPostAction.php new file mode 100644 index 000000000..f20a6008a --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/AdminPostAction.php @@ -0,0 +1,108 @@ +hookName, + $this->callable, + $message, + $this->errorMessage + ); + } + + public function withErrorMessage(string $message): self + { + return new self( + $this->hookName, + $this->callable, + $this->successfulMessage, + $message + ); + } + + public function buildUrl(): string + { + $queryArgs = [ + 'action' => $this->hookName, + ]; + + $referer = remove_query_arg($this->hookName); + if ($referer) { + $queryArgs['_wp_http_referer'] = urlencode($referer); + } + + return wp_nonce_url( + add_query_arg($queryArgs, admin_url('admin-post.php')), + $this->hookName + ); + } + + public function register(): void + { + add_action( + 'admin_post_' . $this->hookName, + $this->buildCallback() + ); + + add_action('admin_notices', function () { + $this->printNotice(); + }); + } + + private function buildCallback(): callable + { + return function (): void { + check_admin_referer($this->hookName); + + $result = ($this->callable)(); + + wp_safe_redirect( + add_query_arg([$this->hookName => $result], wp_get_referer()) + ); + exit; + }; + } + + private function printNotice(): void + { + $result = filter_input(INPUT_GET, $this->hookName, FILTER_VALIDATE_BOOL); + if ($result === null) { + return; + } + + $message = $result ? $this->successfulMessage : $this->errorMessage; + if (!$message) { + return; + } + + printf( + '

%s

', + esc_attr($result ? 'success' : 'error'), + esc_html($message) + ); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/MenuItem.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/MenuItem.php new file mode 100644 index 000000000..0b4c9ed45 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Dashboard/AdminBar/MenuItem.php @@ -0,0 +1,39 @@ +id; + } + + public function title(): string + { + return $this->title; + } + + public function href(): string + { + return $this->href; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/EventDispatcher/WordPressHookEventDispatcher.php b/vendor/rrze/fau-studium-common/src/Infrastructure/EventDispatcher/WordPressHookEventDispatcher.php new file mode 100644 index 000000000..376dbef70 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/EventDispatcher/WordPressHookEventDispatcher.php @@ -0,0 +1,18 @@ +arguments; + } + + $this->decorated->log($level, $message, $context); + + if (!$isCli) { + return; + } + + self::outputToConsole((string) $message, (string) $level); + } + + private static function outputToConsole(string $message, string $level): void + { + switch ($level) { + case LogLevel::EMERGENCY: + case LogLevel::ALERT: + case LogLevel::CRITICAL: + WP_CLI::error($message); + break; + case LogLevel::ERROR: + WP_CLI::error($message, false); + break; + case LogLevel::WARNING: + WP_CLI::warning($message); + break; + case LogLevel::DEBUG: + WP_CLI::debug($message); + break; + case LogLevel::INFO: + WP_CLI::success($message); + break; + default: + WP_CLI::log($message); + } + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Logger/WordPressLogger.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Logger/WordPressLogger.php new file mode 100644 index 000000000..c0d4816f5 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Logger/WordPressLogger.php @@ -0,0 +1,87 @@ +isDebugMode()) { + return; + } + + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log + error_log( + $this->prepareLogEntry((string) $level, (string) $message, $context) + ); + + $context['plugin'] = $this->package; + do_action( + self::buildRrzeLogActionName((string) $level), + (string) $message, + $context + ); + } + + private function prepareLogEntry(string $level, string $message, array $context): string + { + $parts = [ + sprintf('[%s] [%s]: %s', strtoupper($level), $this->package, $message), + ]; + + if (isset($context['exception']) && $context['exception'] instanceof Throwable) { + $exception = $context['exception']; + unset($context['exception']); + + $parts[] = $exception->getMessage(); + $parts[] = $exception->getTraceAsString(); + } + + $context['site_url'] = home_url(); + + $parts[] = json_encode($context); + + return implode("\n", $parts); + } + + private function isDebugMode(): bool + { + /** @psalm-suppress TypeDoesNotContainType */ + return defined('WP_DEBUG') && WP_DEBUG; + } + + /** + * @link https://gitlab.rrze.fau.de/rrze-webteam/rrze-log + */ + private static function buildRrzeLogActionName(string $level): string + { + $rrzeLevel = match ($level) { + LogLevel::EMERGENCY, LogLevel::ALERT, LogLevel::CRITICAL, LogLevel::ERROR => 'error', + LogLevel::WARNING => 'warning', + LogLevel::NOTICE => 'notice', + default => 'info', + }; + + return 'rrze.log.' . $rrzeLevel; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Queue/SyncMessageBus.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Queue/SyncMessageBus.php new file mode 100644 index 000000000..a231d2a93 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Queue/SyncMessageBus.php @@ -0,0 +1,21 @@ +messageHandler->handle($message); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Queue/WpCronMessageBus.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Queue/WpCronMessageBus.php new file mode 100644 index 000000000..b7d34b0f2 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Queue/WpCronMessageBus.php @@ -0,0 +1,26 @@ +jsonSerializer->serialize($message)] + ); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/BilingualRepository.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/BilingualRepository.php new file mode 100644 index 000000000..cc76f3fdc --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/BilingualRepository.php @@ -0,0 +1,188 @@ +idGenerator->generateTermId($term, 'name'), + $term->name, + (string) get_term_meta( + $term->term_id, + self::addEnglishSuffix('name'), + true + ) + ); + } + + final protected function bilingualTermsList(WP_Post $post, string $taxonomy): MultilingualList + { + $terms = get_the_terms($post, $taxonomy); + if (!is_array($terms)) { + return MultilingualList::new(); + } + + $strings = []; + foreach ($terms as $term) { + $strings[] = $this->bilingualTermName($term); + } + + return MultilingualList::new(...$strings); + } + + final protected function bilingualTermMeta(?WP_Term $term, string $key): MultilingualString + { + if (!$term instanceof WP_Term) { + return MultilingualString::empty(); + } + + return MultilingualString::fromTranslations( + $this->idGenerator->generateTermMetaId($term, $key), + (string) get_term_meta($term->term_id, $key, true), + (string) get_term_meta($term->term_id, self::addEnglishSuffix($key), true), + ); + } + + final protected function bilingualPostMeta(?WP_Post $post, string $key): MultilingualString + { + if (!$post instanceof WP_Post) { + return MultilingualString::empty(); + } + + return MultilingualString::fromTranslations( + $this->idGenerator->generatePostMetaId($post, $key), + (string) get_post_meta($post->ID, $key, true), + (string) get_post_meta($post->ID, self::addEnglishSuffix($key), true), + ); + } + + final protected function saveBilingualPostMeta( + int $postId, + MultilingualString $multilingualString + ): void { + + [ + 'type' => $type, + 'entityId' => $parsedPostId, + 'subField' => $key, + ] = $this->idGenerator->parseId($multilingualString->id()); + + if ($type !== 'post_meta' || !$key) { + throw new RuntimeException( + sprintf( + 'Could not save multilingual string with id %s as post meta.', + $multilingualString->id() + ) + ); + } + + if ($postId !== (int) $parsedPostId) { + throw new RuntimeException( + sprintf( + 'Could not save multilingual string with id %s as post meta for post %d.', + $multilingualString->id(), + $postId + ) + ); + } + + update_post_meta($postId, $key, $multilingualString->inGerman()); + update_post_meta($postId, self::addEnglishSuffix($key), $multilingualString->inEnglish()); + } + + final protected function bilingualOption(string $key): MultilingualString + { + $optionKey = self::addOptionPrefix($key); + $option = (array) get_option($optionKey, []); + + return MultilingualString::fromTranslations( + $this->idGenerator->generateOptionId($optionKey), + (string) ($option[MultilingualString::DE] ?? ''), + (string) ($option[MultilingualString::EN] ?? ''), + ); + } + + final protected function bilingualLinkFromTerm(?WP_Term $term): MultilingualLink + { + return MultilingualLink::new( + $term instanceof WP_Term ? $this->idGenerator->generateTermId($term) : '', + name: $this->bilingualTermName($term), + linkText: $this->bilingualTermMeta($term, MultilingualLink::LINK_TEXT), + linkUrl: $this->bilingualTermMeta($term, MultilingualLink::LINK_URL), + ); + } + + final protected function bilingualTermLinks(WP_Post $post, string $taxonomy): MultilingualLinks + { + $terms = get_the_terms($post, $taxonomy); + if (!is_array($terms)) { + return MultilingualLinks::new(); + } + + $links = []; + foreach ($terms as $term) { + $links[] = $this->bilingualLinkFromTerm($term); + } + + return MultilingualLinks::new(...$links); + } + + final protected function bilingualLinkFromOption(string $key): MultilingualLink + { + $optionKey = self::addOptionPrefix($key); + // TODO: is it ok to have this settings serialized? Maybe yes. + $option = (array) get_option($optionKey, []); + + return MultilingualLink::new( + $this->idGenerator->generateOptionId($optionKey), + name: MultilingualString::fromTranslations( + $this->idGenerator->generateOptionId($optionKey, MultilingualLink::NAME), + (string) ($option[MultilingualLink::NAME] ?? ''), + (string) ($option[self::addEnglishSuffix(MultilingualLink::NAME)] ?? ''), + ), + linkText: MultilingualString::fromTranslations( + $this->idGenerator->generateOptionId($optionKey, MultilingualLink::LINK_TEXT), + (string) ($option[MultilingualLink::LINK_TEXT] ?? ''), + (string) ($option[self::addEnglishSuffix(MultilingualLink::LINK_TEXT)] ?? ''), + ), + linkUrl: MultilingualString::fromTranslations( + $this->idGenerator->generateOptionId($optionKey, MultilingualLink::LINK_URL), + (string) ($option[MultilingualLink::LINK_URL] ?? ''), + (string) ($option[self::addEnglishSuffix(MultilingualLink::LINK_URL)] ?? ''), + ), + ); + } + + public static function addEnglishSuffix(string $key): string + { + return $key . '_' . MultilingualString::EN; + } + + public static function addOptionPrefix(string $key): string + { + return self::OPTION_PREFIX . '_' . $key; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/CampoKeysRepository.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/CampoKeysRepository.php new file mode 100644 index 000000000..3031a4570 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/CampoKeysRepository.php @@ -0,0 +1,110 @@ + DegreeProgram::DEGREE, + StudyLocationTaxonomy::KEY => DegreeProgram::LOCATION, + AreaOfStudyTaxonomy::KEY => DegreeProgram::AREA_OF_STUDY, + ]; + + public const CAMPO_KEY_TERM_META_KEY = 'uniquename'; + + public function degreeProgramCampoKeys(DegreeProgramId $degreeProgramId): CampoKeys + { + /** @var WP_Error|array $terms */ + $terms = wp_get_post_terms( + $degreeProgramId->asInt(), + array_keys(self::TAXONOMY_TO_CAMPO_KEY_MAP) + ); + + if ($terms instanceof WP_Error) { + return CampoKeys::empty(); + } + + $map = []; + + foreach ($terms as $term) { + $campoKey = (string) get_term_meta($term->term_id, self::CAMPO_KEY_TERM_META_KEY, true); + + if (empty($campoKey)) { + continue; + } + + $campoKeyType = self::TAXONOMY_TO_CAMPO_KEY_MAP[$term->taxonomy] ?? null; + + if (is_null($campoKeyType)) { + continue; + } + + $map[$campoKeyType] = $campoKey; + } + + return CampoKeys::fromArray($map); + } + + /** + * Return a map of taxonomy keys to terms based on a given HIS code. + * + * @throws RuntimeException + * @return array + */ + public function taxonomyToTermsMapFromCampoKeys(CampoKeys $campoKeys): array + { + $result = []; + + $campoKeys = $campoKeys->asArray(); + + foreach (self::TAXONOMY_TO_CAMPO_KEY_MAP as $taxonomy => $campoKeyType) { + $campoKey = $campoKeys[$campoKeyType] ?? ''; + + if ($campoKey === '') { + continue; + } + + $term = $this->findTermByCampoKey($taxonomy, $campoKey); + + if (! $term instanceof WP_Term) { + throw new RuntimeException('Could not find term for Campo key: ' . $campoKey); + } + + $result[$taxonomy] = $term->term_id; + } + + return $result; + } + + private function findTermByCampoKey(string $taxonomy, string $campoKey): ?WP_Term + { + if ($campoKey === '') { + return null; + } + + /** @var WP_Error|array $terms */ + $terms = get_terms([ + 'taxonomy' => $taxonomy, + 'meta_key' => self::CAMPO_KEY_TERM_META_KEY, + 'meta_value' => $campoKey, + ]); + + if ($terms instanceof WP_Error) { + return null; + } + + return $terms[0] ?? null; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/FacultyRepository.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/FacultyRepository.php new file mode 100644 index 000000000..ee08a021b --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/FacultyRepository.php @@ -0,0 +1,29 @@ +id()->asInt(), + FacultyTaxonomy::KEY + ); + + if (!is_array($terms)) { + return ArrayOfStrings::new(); + } + + /** @var array $slugs */ + $slugs = wp_list_pluck($terms, 'slug'); + + return ArrayOfStrings::new(...$slugs); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/IdGenerator.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/IdGenerator.php new file mode 100644 index 000000000..d173799d1 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/IdGenerator.php @@ -0,0 +1,139 @@ +generateId( + 'term', + $term instanceof WP_Term ? $term->term_id : $term, + $field + ); + } + + public function generateTermMetaId(WP_Term|int $term, string $key): string + { + return $this->generateId( + 'term_meta', + $term instanceof WP_Term ? $term->term_id : $term, + $key + ); + } + + public function generatePostId(WP_Post|int $post, string $field = ''): string + { + return $this->generateId( + 'post', + $post instanceof WP_Post ? $post->ID : $post, + $field + ); + } + + public function generatePostMetaId(WP_Post|int $post, string $key): string + { + return $this->generateId( + 'post_meta', + $post instanceof WP_Post ? $post->ID : $post, + $key + ); + } + + public function generateOptionId(string $optionKey, string $subField = ''): string + { + return $this->generateId('option', $optionKey, $subField); + } + + /** + * @psalm-param 'post' | 'post_meta' | 'term' | 'term_meta' | 'option' $type + */ + private function generateId(string $type, int|string $entityId, string $subField = ''): string + { + $parts = [ + $type, + (string) $entityId, + ]; + if ($subField) { + $parts[] = $subField; + } + + return implode(':', $parts); + } + + /** + * @psalm-return array{type: string, entityId: string, subField: string|null} + */ + public function parseId(string $id): array + { + $parts = explode(':', $id); + + return [ + 'type' => $parts[0] ?? '', + 'entityId' => $parts[1] ?? '', + 'subField' => $parts[2] ?? null, + ]; + } + + /** + * @return list + */ + public function termIdsList( + MultilingualString|MultilingualList|MultilingualLink|MultilingualLinks|NumberOfStudents|Degree|AdmissionRequirement $structure + ): array { + + $ids = $this->retrieveIds($structure); + + $validatedIds = []; + foreach ($ids as $id) { + if (!$id) { + continue; + } + + ['type' => $type, 'entityId' => $termId] = $this->parseId($id); + if ($type !== 'term' || (int) $termId < 1) { + throw new RuntimeException( + sprintf( + 'Could not assign %s structure %s as terms.', + $structure::class, + (string) json_encode($structure) + ) + ); + } + + $validatedIds[] = (int) $termId; + } + + return $validatedIds; + } + + private function retrieveIds( + MultilingualString|MultilingualList|MultilingualLink|MultilingualLinks|NumberOfStudents|Degree|AdmissionRequirement $structure + ): ArrayOfStrings { + + if ($structure instanceof MultilingualList || $structure instanceof MultilingualLinks) { + return ArrayOfStrings::new( + ...array_map( + static fn(MultilingualString|MultilingualLink $item) => $item->id(), + $structure->getArrayCopy() + ) + ); + } + + return ArrayOfStrings::new($structure->id()); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/StickyDegreeProgramRepository.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/StickyDegreeProgramRepository.php new file mode 100644 index 000000000..4a6cab460 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/StickyDegreeProgramRepository.php @@ -0,0 +1,33 @@ +isSticky($postId, $term) + ? delete_post_meta($postId, self::stickyKey($term)) !== false + : update_post_meta($postId, self::stickyKey($term), true) !== false; + } + + public function isSticky(int $postId, ?WP_Term $term): bool + { + return (bool) get_post_meta($postId, self::stickyKey($term), true); + } + + public static function stickyKey(?WP_Term $term): string + { + $pieces = ['_sticky']; + if ($term instanceof WP_Term) { + $pieces[] = $term->taxonomy; + $pieces[] = $term->term_id; + } + + return implode('_', $pieces); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramCollectionRepository.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramCollectionRepository.php new file mode 100644 index 000000000..19023bd74 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramCollectionRepository.php @@ -0,0 +1,78 @@ +querySplitter->maybeSplitQuery($criteria); + /** @var array $ids */ + $ids = $query->query( + $this->queryArgsBuilder + ->build($criteria) + ->args() + ); + + $items = []; + foreach ($ids as $id) { + $view = $this->degreeProgramViewRepository->findRaw( + DegreeProgramId::fromInt($id), + ); + + if ($view instanceof DegreeProgramViewRaw) { + $items[] = $view; + } + } + + return new WpQueryPaginationAwareCollection($query, ...$items); + } + + public function findTranslatedCollection(CollectionCriteria $criteria, string $languageCode): PaginationAwareCollection + { + $query = new WP_Query(); + $criteria = $this->querySplitter->maybeSplitQuery( + $criteria->withLanguage($languageCode) + ); + + /** @var array $ids */ + $ids = $query->query( + $this->queryArgsBuilder + ->build($criteria->withLanguage($languageCode)) + ->args() + ); + + $items = []; + foreach ($ids as $id) { + $view = $this->degreeProgramViewRepository->findTranslated( + DegreeProgramId::fromInt($id), + $languageCode + ); + + if ($view instanceof DegreeProgramViewTranslated) { + $items[] = $view; + } + } + + return new WpQueryPaginationAwareCollection($query, ...$items); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramRepository.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramRepository.php new file mode 100644 index 000000000..4bd3cc8dd --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramRepository.php @@ -0,0 +1,558 @@ +asInt(); + $post = get_post($postId); + + if (!$post instanceof WP_Post || $post->post_type !== DegreeProgramPostType::KEY) { + throw new RuntimeException('Could not find degree program with id ' . (string) $postId); + } + + $featuredImageId = (int) get_post_thumbnail_id($post); + $teaserImageId = (int) get_post_meta($postId, DegreeProgram::TEASER_IMAGE, true); + + /** + * @var string $videos + */ + $videos = get_post_meta($postId, DegreeProgram::VIDEOS, true); + + return new DegreeProgram( + id: $degreeProgramId, + slug: MultilingualString::fromTranslations( + $this->idGenerator->generatePostId($post, 'post_name'), + $post->post_name, + (string) get_post_meta( + $postId, + BilingualRepository::addEnglishSuffix('post_name'), + true, + ), + ), + featuredImage: Image::new( + $featuredImageId, + (string) wp_get_attachment_image_url($featuredImageId, 'full') + ), + teaserImage: Image::new( + $teaserImageId, + (string) wp_get_attachment_image_url($teaserImageId, 'full') + ), + title: MultilingualString::fromTranslations( + $this->idGenerator->generatePostId($post, 'title'), + $post->post_status !== 'auto-draft' ? $post->post_title : '', + (string) get_post_meta( + $postId, + BilingualRepository::addEnglishSuffix('title'), + true, + ), + ), + subtitle: $this->bilingualPostMeta($post, DegreeProgram::SUBTITLE), + standardDuration: + (string) get_post_meta($postId, DegreeProgram::STANDARD_DURATION, true), + start: $this->bilingualTermsList($post, SemesterTaxonomy::KEY), + numberOfStudents: $this->numberOfStudents($post), + teachingLanguage: $this->bilingualTermName( + $this->firstTerm($post, TeachingLanguageTaxonomy::KEY) + ), + attributes: $this->bilingualTermsList($post, AttributeTaxonomy::KEY), + degree: $this->degree($post), + faculty: $this->bilingualTermLinks($post, FacultyTaxonomy::KEY), + location: $this->bilingualTermsList($post, StudyLocationTaxonomy::KEY), + subjectGroups: $this->bilingualTermsList($post, SubjectGroupTaxonomy::KEY), + videos: ArrayOfStrings::new( + ...array_map( + 'strval', + array_filter(explode(',', $videos)) + ) + ), + metaDescription: $this->bilingualPostMeta($post, DegreeProgram::META_DESCRIPTION), + keywords: $this->bilingualTermsList($post, KeywordTaxonomy::KEY), + areaOfStudy: $this->bilingualTermLinks($post, AreaOfStudyTaxonomy::KEY), + entryText: $this->bilingualPostMeta($post, DegreeProgram::ENTRY_TEXT), + content: Content::new( + about: $this->contentItem($post, Content::ABOUT), + structure: $this->contentItem($post, Content::STRUCTURE), + specializations: $this->contentItem($post, Content::SPECIALIZATIONS), + qualitiesAndSkills: $this->contentItem($post, Content::QUALITIES_AND_SKILLS), + whyShouldStudy: $this->contentItem($post, Content::WHY_SHOULD_STUDY), + careerProspects: $this->contentItem($post, Content::CAREER_PROSPECTS), + specialFeatures: $this->contentItem($post, Content::SPECIAL_FEATURES), + testimonials: $this->contentItem($post, Content::TESTIMONIALS), + ), + admissionRequirements: AdmissionRequirements::new( + bachelorOrTeachingDegree: $this->admissionRequirement( + $this->firstTerm( + $post, + BachelorOrTeachingDegreeAdmissionRequirementTaxonomy::KEY + ) + ), + teachingDegreeHigherSemester: $this->admissionRequirement( + $this->firstTerm( + $post, + TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy::KEY + ) + ), + master: $this->admissionRequirement( + $this->firstTerm( + $post, + MasterDegreeAdmissionRequirementTaxonomy::KEY, + ) + ), + ), + contentRelatedMasterRequirements: $this->bilingualPostMeta( + $post, + DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS + ), + applicationDeadlineWinterSemester: (string) get_post_meta( + $postId, + DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER, + true + ), + applicationDeadlineSummerSemester: (string) get_post_meta( + $postId, + DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER, + true + ), + detailsAndNotes: $this->bilingualPostMeta($post, DegreeProgram::DETAILS_AND_NOTES), + languageSkills: $this->bilingualPostMeta($post, DegreeProgram::LANGUAGE_SKILLS), + languageSkillsHumanitiesFaculty: (string) get_post_meta( + $postId, + DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY, + true + ), + germanLanguageSkillsForInternationalStudents: $this->bilingualLinkFromTerm( + $this->firstTerm( + $post, + GermanLanguageSkillsForInternationalStudentsTaxonomy::KEY, + ) + ), + startOfSemester: $this->bilingualLinkFromOption(DegreeProgram::START_OF_SEMESTER), + semesterDates: $this->bilingualLinkFromOption(DegreeProgram::SEMESTER_DATES), + examinationsOffice: $this->bilingualLinkFromTerm( + $this->firstTerm($post, ExaminationsOfficeTaxonomy::KEY) + ), + examinationRegulations: (string) get_post_meta( + $postId, + DegreeProgram::EXAMINATION_REGULATIONS, + true + ), + moduleHandbook: (string) get_post_meta( + $postId, + DegreeProgram::MODULE_HANDBOOK, + true + ), + url: $this->bilingualPostMeta($post, DegreeProgram::URL), + department: $this->bilingualPostMeta($post, DegreeProgram::DEPARTMENT), + studentAdvice: $this->bilingualLinkFromOption(DegreeProgram::STUDENT_ADVICE), + subjectSpecificAdvice: $this->bilingualLinkFromTerm( + $this->firstTerm($post, SubjectSpecificAdviceTaxonomy::KEY) + ), + serviceCenters: $this->bilingualLinkFromOption(DegreeProgram::SERVICE_CENTERS), + infoBrochure: (string) get_post_meta( + $postId, + DegreeProgram::INFO_BROCHURE, + true + ), + semesterFee: $this->bilingualLinkFromOption(DegreeProgram::SEMESTER_FEE), + feeRequired: (bool) get_post_meta( + $postId, + DegreeProgram::FEE_REQUIRED, + true + ), + degreeProgramFees: $this->bilingualPostMeta( + $post, + DegreeProgram::DEGREE_PROGRAM_FEES + ), + abroadOpportunities: $this->bilingualLinkFromOption( + DegreeProgram::ABROAD_OPPORTUNITIES + ), + notesForInternationalApplicants: $this->bilingualLinkFromOption( + DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS + ), + studentInitiatives: $this->bilingualLinkFromOption( + DegreeProgram::STUDENT_INITIATIVES + ), + applyNowLink: $this->bilingualLinkFromTerm( + $this->firstTerm($post, ApplyNowLinkTaxonomy::KEY), + ), + combinations: $this->idsFromPostMeta($postId, DegreeProgram::COMBINATIONS), + limitedCombinations: $this->idsFromPostMeta( + $postId, + DegreeProgram::LIMITED_COMBINATIONS + ), + campoKeys: $this->campoKeysRepository->degreeProgramCampoKeys($degreeProgramId), + ); + } + + private function numberOfStudents(WP_Post $post): NumberOfStudents + { + $firstTerm = $this->firstTerm($post, NumberOfStudentsTaxonomy::KEY); + if (!$firstTerm instanceof WP_Term) { + return NumberOfStudents::empty(); + } + + return NumberOfStudents::new( + $this->idGenerator->generateTermId($firstTerm), + $firstTerm->name, + term_description($firstTerm->term_id) + ); + } + + private function firstTerm(WP_Post $post, string $taxonomy): ?WP_Term + { + $terms = get_the_terms($post, $taxonomy); + if (!is_array($terms)) { + return null; + } + + if (!isset($terms[0]) || !$terms[0] instanceof WP_Term) { + return null; + } + + return $terms[0]; + } + + private function degree(WP_Post $post): Degree + { + $term = $this->firstTerm($post, DegreeTaxonomy::KEY); + + if (!$term instanceof WP_Term) { + return Degree::empty(); + } + + return $this->degreeFromTerm($term); + } + + private function degreeFromTerm(WP_Term $term): Degree + { + $parent = get_term($term->parent); + + return Degree::new( + $this->idGenerator->generateTermId($term), + $this->bilingualTermName($term), + $this->bilingualTermMeta($term, Degree::ABBREVIATION), + $parent instanceof WP_Term ? $this->degreeFromTerm($parent) : null, + ); + } + + private function admissionRequirement(?WP_Term $term): AdmissionRequirement + { + if (!$term instanceof WP_Term) { + return AdmissionRequirement::empty(); + } + + $parent = $term->parent ? get_term($term->parent) : null; + + return AdmissionRequirement::new( + $this->bilingualLinkFromTerm($term), + $parent instanceof WP_Term ? $this->admissionRequirement($parent) : null, + $term->slug + ); + } + + private function contentItem(WP_Post $post, string $key): ContentItem + { + return ContentItem::new( + $this->bilingualOption($key), + $this->bilingualPostMeta($post, $key), + ); + } + + private function idsFromPostMeta(int $postId, string $key): DegreeProgramIds + { + $metas = (array) get_post_meta($postId, $key); + $result = []; + foreach ($metas as $meta) { + $castedMeta = (int) $meta; + if ($castedMeta === 0) { + continue; + } + + $result[] = $castedMeta; + } + + return DegreeProgramIds::fromArray($result); + } + + /** + * While it violates the DDD consistency principle, we save the Degree Program entity + * only partially to leverage WordPress functionality provided out-of-the-box. + * + * We only save post metas and assign terms to the WordPress post. + * Native post properties like post title are saved by WordPress functionality. + * Shared properties like term metas and options are saved separately. + */ + public function save(DegreeProgram $degreeProgram): void + { + + $degreeProgramViewRaw = DegreeProgramViewRaw::fromDegreeProgram($degreeProgram); + $postId = $degreeProgramViewRaw->id()->asInt(); + + wp_update_post([ + 'ID' => $postId, + 'post_title' => $degreeProgramViewRaw->title()->inGerman(), + 'post_name' => $this->generateSlug( + $degreeProgramViewRaw, + MultilingualString::DE + ), + ]); + + $this->persistFeatureImage( + $postId, + $degreeProgramViewRaw->featuredImage()->id() + ); + + $metas = [ + DegreeProgram::TEASER_IMAGE => + $degreeProgramViewRaw->teaserImage()->id(), + BilingualRepository::addEnglishSuffix('title') => + $degreeProgramViewRaw->title()->inEnglish(), + BilingualRepository::addEnglishSuffix('post_name') => + $this->generateSlug( + $degreeProgramViewRaw, + MultilingualString::EN + ), + DegreeProgram::STANDARD_DURATION => + $degreeProgramViewRaw->standardDuration(), + DegreeProgram::FEE_REQUIRED => + $degreeProgramViewRaw->isFeeRequired(), + DegreeProgram::VIDEOS => + implode( + ',', + array_map( + [$this->fieldsSanitizer, 'sanitizeUrlField'], + $degreeProgramViewRaw->videos()->getArrayCopy(), + ), + ), + DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER => + $degreeProgramViewRaw->applicationDeadlineWinterSemester(), + DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER => + $degreeProgramViewRaw->applicationDeadlineSummerSemester(), + DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY => + $degreeProgramViewRaw->languageSkillsHumanitiesFaculty(), + DegreeProgram::MODULE_HANDBOOK => + $this->fieldsSanitizer->sanitizeUrlField( + $degreeProgramViewRaw->moduleHandbook() + ), + DegreeProgram::INFO_BROCHURE => + $this->fieldsSanitizer->sanitizeUrlField( + $degreeProgramViewRaw->infoBrochure() + ), + DegreeProgram::EXAMINATION_REGULATIONS => + $this->fieldsSanitizer->sanitizeUrlField( + $degreeProgramViewRaw->examinationRegulations() + ), + ]; + + foreach ($metas as $key => $value) { + update_post_meta($postId, $key, $value); + } + + $content = $degreeProgramViewRaw->content(); + $bilingualMetas = [ + $degreeProgramViewRaw->subtitle(), + $this->fieldsSanitizer->sanitizeMultiLingualTextField( + $degreeProgramViewRaw->metaDescription() + ), + $content->about()->description(), + $content->structure()->description(), + $content->specializations()->description(), + $content->qualitiesAndSkills()->description(), + $content->whyShouldStudy()->description(), + $content->careerProspects()->description(), + $content->specialFeatures()->description(), + $content->testimonials()->description(), + $degreeProgramViewRaw->contentRelatedMasterRequirements(), + $degreeProgramViewRaw->detailsAndNotes(), + $degreeProgramViewRaw->languageSkills(), + $this->fieldsSanitizer->sanitizeMultilingualUrlField( + $degreeProgramViewRaw->url() + ), + $this->fieldsSanitizer->sanitizeMultiLingualTextField( + $degreeProgramViewRaw->degreeProgramFees() + ), + $this->fieldsSanitizer->sanitizeMultilingualUrlField( + $degreeProgramViewRaw->department() + ), + $degreeProgramViewRaw->entryText(), + ]; + + foreach ($bilingualMetas as $bilingualMeta) { + $this->saveBilingualPostMeta($postId, $bilingualMeta); + } + + $admissionRequirements = $degreeProgramViewRaw->admissionRequirements(); + $terms = [ + SemesterTaxonomy::KEY => + $degreeProgramViewRaw->start(), + NumberOfStudentsTaxonomy::KEY => + $degreeProgramViewRaw->numberOfStudents(), + TeachingLanguageTaxonomy::KEY => + $degreeProgramViewRaw->teachingLanguage(), + AttributeTaxonomy::KEY => + $degreeProgramViewRaw->attributes(), + DegreeTaxonomy::KEY => + $degreeProgramViewRaw->degree(), + FacultyTaxonomy::KEY => + $degreeProgramViewRaw->faculty(), + StudyLocationTaxonomy::KEY => + $degreeProgramViewRaw->location(), + SubjectGroupTaxonomy::KEY => + $degreeProgramViewRaw->subjectGroups(), + BachelorOrTeachingDegreeAdmissionRequirementTaxonomy::KEY => + $admissionRequirements->bachelorOrTeachingDegree(), + TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy::KEY => + $admissionRequirements->teachingDegreeHigherSemester(), + MasterDegreeAdmissionRequirementTaxonomy::KEY => + $admissionRequirements->master(), + GermanLanguageSkillsForInternationalStudentsTaxonomy::KEY => + $degreeProgramViewRaw->germanLanguageSkillsForInternationalStudents(), + ExaminationsOfficeTaxonomy::KEY => + $degreeProgramViewRaw->examinationsOffice(), + SubjectSpecificAdviceTaxonomy::KEY => + $degreeProgramViewRaw->subjectSpecificAdvice(), + KeywordTaxonomy::KEY => + $degreeProgramViewRaw->keywords(), + AreaOfStudyTaxonomy::KEY => + $degreeProgramViewRaw->areaOfStudy(), + ApplyNowLinkTaxonomy::KEY => + $degreeProgramViewRaw->applyNowLink(), + ]; + + foreach ($terms as $taxonomy => $multilingualStructure) { + wp_set_object_terms( + $postId, + $this->idGenerator->termIdsList($multilingualStructure), + $taxonomy + ); + } + + $data = $degreeProgram->asArray(); + $this->persistCombinations( + $postId, + DegreeProgram::COMBINATIONS, + $data[DegreeProgram::COMBINATIONS_CHANGESET], + ); + $this->persistCombinations( + $postId, + DegreeProgram::LIMITED_COMBINATIONS, + $data[DegreeProgram::LIMITED_COMBINATIONS_CHANGESET], + ); + + foreach ($degreeProgram->releaseEvents() as $event) { + $this->eventDispatcher->dispatch($event); + } + } + + private function persistFeatureImage(int $postId, int $featureImageId): void + { + if ($featureImageId) { + set_post_thumbnail($postId, $featureImageId); + return; + } + + delete_post_thumbnail($postId); + } + + /** + * Bidirectional many-to-many relationship implementation. + */ + private function persistCombinations( + int $postId, + string $key, + IntegersListChangeset $arrayChangeset + ): void { + + foreach ($arrayChangeset->removed() as $item) { + delete_post_meta($postId, $key, $item); + delete_post_meta($item, $key, $postId); + } + + foreach ($arrayChangeset->added() as $item) { + add_post_meta($postId, $key, $item); + add_post_meta($item, $key, $postId); + } + } + + /** + * @psalm-param LanguageCodes $languageCode + */ + private function generateSlug( + DegreeProgramViewRaw $degreeProgramViewRaw, + string $languageCode + ): string { + + return sanitize_title( + sprintf( + "%s-%s", + $degreeProgramViewRaw->title()->asString($languageCode), + str_replace( + ['.', '-', ','], + '', + $degreeProgramViewRaw->degree()->abbreviation()->asString($languageCode) + ) + ) + ); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramViewRepository.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramViewRepository.php new file mode 100644 index 000000000..7d32c54be --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramViewRepository.php @@ -0,0 +1,316 @@ +degreeProgramRepository->getById($degreeProgramId); + return DegreeProgramViewRaw::fromDegreeProgram($degreeProgram); + } catch (RuntimeException) { + return null; + } + } + + /** + * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + public function findTranslated( + DegreeProgramId $degreeProgramId, + string $languageCode + ): ?DegreeProgramViewTranslated { + + $raw = $this->findRaw($degreeProgramId); + if (!$raw instanceof DegreeProgramViewRaw) { + return null; + } + + $raw = $this->conditionalFieldsFilter->filter( + $raw, + $this->facultyRepository->findFacultySlugs($raw), + ); + + $main = $this->translateDegreeProgram($raw, $languageCode); + foreach (MultilingualString::LANGUAGES as $code => $name) { + if ($code === $languageCode) { + continue; + } + + $main = $main->withTranslation( + $this->translateDegreeProgram($raw, $code), + $code + ); + } + + return $main; + } + + /** + * @psalm-param LanguageCodes $languageCode + */ + private function translateDegreeProgram( + DegreeProgramViewRaw $raw, + string $languageCode + ): DegreeProgramViewTranslated { + + $title = $raw->title()->asString($languageCode); + $admissionRequirementsTranslated = AdmissionRequirementsTranslated::fromAdmissionRequirements( + $raw->admissionRequirements(), + $languageCode + ); + + return new DegreeProgramViewTranslated( + id: $raw->id(), + link: $this->link( + $raw->id()->asInt(), + $raw->slug(), + $languageCode, + ), + slug: $raw->slug()->asString($languageCode), + lang: $languageCode, + featuredImage: $this->imageView( + $raw->featuredImage(), + DegreeProgram::FEATURED_IMAGE, + $title + ), + teaserImage: $this->imageView( + $raw->teaserImage(), + DegreeProgram::TEASER_IMAGE, + $title + ), + title: $raw->title()->asString($languageCode), + subtitle: $raw->subtitle()->asString($languageCode), + standardDuration: $raw->standardDuration(), + feeRequired: $raw->isFeeRequired(), + start: $raw->start()->asArrayOfStrings($languageCode), + numberOfStudents: $raw->numberOfStudents(), + teachingLanguage: $raw->teachingLanguage()->asString($languageCode), + attributes: $raw->attributes()->asArrayOfStrings($languageCode), + degree: DegreeTranslated::fromDegree($raw->degree(), $languageCode), + faculty: Links::fromMultilingualLinks($raw->faculty(), $languageCode), + location: $raw->location()->asArrayOfStrings($languageCode), + subjectGroups: $raw->subjectGroups()->asArrayOfStrings($languageCode), + videos: $raw->videos(), + metaDescription: $raw->metaDescription()->asString($languageCode), + content: ContentTranslated::fromContent($raw->content(), $languageCode) + ->mapDescriptions([$this, 'formatContentField']), + admissionRequirements: $admissionRequirementsTranslated, + admissionRequirementLink: $this->admissionRequirementLink( + $admissionRequirementsTranslated, + $languageCode + ), + contentRelatedMasterRequirements: $this->formatContentField( + $raw->contentRelatedMasterRequirements()->asString($languageCode) + ), + applicationDeadlineWinterSemester: $this->formatContentField( + $raw->applicationDeadlineWinterSemester() + ), + applicationDeadlineSummerSemester: $this->formatContentField( + $raw->applicationDeadlineSummerSemester() + ), + detailsAndNotes: $this->formatContentField( + $raw->detailsAndNotes()->asString($languageCode) + ), + languageSkills: $this->formatContentField( + $raw->languageSkills()->asString($languageCode) + ), + languageSkillsHumanitiesFaculty: $this->formatContentField( + $raw->languageSkillsHumanitiesFaculty() + ), + germanLanguageSkillsForInternationalStudents: Link::fromMultilingualLink( + $raw->germanLanguageSkillsForInternationalStudents(), + $languageCode + ), + startOfSemester: Link::fromMultilingualLink($raw->startOfSemester(), $languageCode), + semesterDates: Link::fromMultilingualLink($raw->semesterDates(), $languageCode), + examinationsOffice: Link::fromMultilingualLink($raw->examinationsOffice(), $languageCode), + examinationRegulations: $raw->examinationRegulations(), + moduleHandbook: $raw->moduleHandbook(), + url: $raw->url()->asString($languageCode), + department: $raw->department()->asString($languageCode), + studentAdvice: Link::fromMultilingualLink($raw->studentAdvice(), $languageCode), + subjectSpecificAdvice: Link::fromMultilingualLink($raw->subjectSpecificAdvice(), $languageCode), + serviceCenters: Link::fromMultilingualLink($raw->serviceCenters(), $languageCode), + infoBrochure: $raw->infoBrochure(), + semesterFee: Link::fromMultilingualLink($raw->semesterFee(), $languageCode), + degreeProgramFees: $raw->degreeProgramFees()->asString($languageCode), + abroadOpportunities: Link::fromMultilingualLink($raw->abroadOpportunities(), $languageCode), + keywords: $raw->keywords()->asArrayOfStrings($languageCode), + areaOfStudy: Links::fromMultilingualLinks($raw->areaOfStudy(), $languageCode), + combinations: $this->relatedDegreePrograms($raw->combinations()->asArray(), $languageCode), + limitedCombinations: $this->relatedDegreePrograms($raw->limitedCombinations()->asArray(), $languageCode), + notesForInternationalApplicants: Link::fromMultilingualLink($raw->notesForInternationalApplicants(), $languageCode), + studentInitiatives: Link::fromMultilingualLink($raw->studentInitiatives(), $languageCode), + applyNowLink: Link::fromMultilingualLink($raw->applyNowLink(), $languageCode), + entryText: $this->formatContentField($raw->entryText()->asString($languageCode)), + campoKeys: $raw->campoKeys(), + ); + } + + /** + * @psalm-param 'featured_image' | 'teaser_image' $type + */ + private function imageView(Image $image, string $type, string $alt): ImageView + { + if (!$image->id()) { + return ImageView::empty(); + } + + return ImageView::new( + $image->id(), + $image->url(), + wp_get_attachment_image( + $image->id(), + (string) apply_filters( + 'fau.degree-program.image-size', + 'full', + $type, + ), + false, + [ + 'alt' => $alt, + ] + ) + ); + } + + private function link(int $id, MultilingualString $slug, string $languageCode): string + { + $permalink = get_the_permalink($id); + if (!$permalink) { + return ''; + } + + if ($languageCode === MultilingualString::DE) { + return $permalink; + } + + return str_replace($slug->inGerman(), $slug->inEnglish(), $permalink); + } + + private function admissionRequirementLink( + AdmissionRequirementsTranslated $admissionRequirementsTranslated, + string $languageCode, + ): ?AdmissionRequirementTranslated { + + $mainLink = $admissionRequirementsTranslated->mainLink(); + if (!$mainLink) { + return null; + } + + $data = $mainLink->asArray(); + $data[AdmissionRequirement::LINK_TEXT] = (string) (get_option( + BilingualRepository::addOptionPrefix( + 'admission_requirement_link_text' + ), + [], + )[$languageCode] ?? ''); + + return AdmissionRequirementTranslated::fromArray($data); + } + + public function formatContentField(string $content): string + { + // Temporarily removes shortcodes generation to allow remove it with sanitizer + remove_filter('the_content', 'do_shortcode', 11); + $content = (string) apply_filters('the_content', $content); + $content = $this->htmlContentSanitizer->sanitizeContentField($content); + add_filter('the_content', 'do_shortcode', 11); + + return do_shortcode($content); + } + + /** + * @param array $ids + */ + private function relatedDegreePrograms(array $ids, string $languageCode): RelatedDegreePrograms + { + $result = []; + foreach ($ids as $id) { + $post = get_post($id); + if (!$post instanceof WP_Post) { + continue; + } + + $result[] = $this->relatedDegreeProgram($post, $languageCode); + } + + usort( + $result, + static fn (RelatedDegreeProgram $degreeProgram1, RelatedDegreeProgram $degreeProgram2) + => strcasecmp($degreeProgram1->title(), $degreeProgram2->title()), + ); + + return RelatedDegreePrograms::new(...$result); + } + + private function relatedDegreeProgram(WP_Post $post, string $languageCode): RelatedDegreeProgram + { + if ($languageCode === MultilingualString::DE) { + return RelatedDegreeProgram::new( + $post->ID, + $post->post_title, + (string) get_the_permalink($post), + ); + } + + return RelatedDegreeProgram::new( + $post->ID, + (string) get_post_meta( + $post->ID, + BilingualRepository::addEnglishSuffix('title'), + true + ), + home_url( + sprintf( + '%s/%s', + DegreeProgramPostType::KEY, + (string) get_post_meta( + $post->ID, + BilingualRepository::addEnglishSuffix('post_name'), + true + ) + ) + ), + ); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryArgs.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryArgs.php new file mode 100644 index 000000000..f2ff171fe --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryArgs.php @@ -0,0 +1,74 @@ +args; + } + + public function arg(string $key): mixed + { + return $this->args[$key] ?? null; + } + + public function withArg(string $key, mixed $value): self + { + $instance = clone $this; + + $instance->args[$key] = $value; + + return $instance; + } + + public function withOrderBy(array $orderBy): self + { + return $this->withArg('orderby', $orderBy); + } + + public function withTaxQueryItem(array $item): self + { + $instance = clone $this; + + $instance->args['tax_query'] = (array) ($instance->args['tax_query'] + ?? ['relation' => 'AND']); + + $instance->args['tax_query'][] = $item; + + return $instance; + } + + public function withMetaQueryItem(array $item): self + { + $instance = clone $this; + + $instance->args['meta_query'] = (array) ($instance->args['meta_query'] + ?? ['relation' => 'AND']); + + $instance->args['meta_query'][] = $item; + + return $instance; + } + + public function withMetaKey(string $metaKey): self + { + $instance = clone $this; + + $instance->args['meta_key'] = $metaKey; + + return $instance; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryArgsBuilder.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryArgsBuilder.php new file mode 100644 index 000000000..4fe1d8784 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryArgsBuilder.php @@ -0,0 +1,335 @@ + 'paged', + 'per_page' => 'posts_per_page', + 'include' => 'post__in', + 'order_by' => 'orderby', + ]; + + private const DEFAULTS = [ + 'post_type' => DegreeProgramPostType::KEY, + 'post_status' => 'publish', + 'fields' => 'ids', + 'update_post_meta_cache' => false, + 'update_post_term_cache' => false, + ]; + + private const DEFAULT_ORDER_BY = [ + DegreeProgram::TITLE => 'asc', + 'date' => 'desc', + ]; + + public function __construct( + private TaxonomiesList $taxonomiesList, + private CampoKeysRepository $campoKeysRepository, + ) { + } + + public function build(CollectionCriteria $criteria): WpQueryArgs + { + $queryArgs = (new WpQueryArgs(self::DEFAULTS)); + + foreach ($criteria->args() as $key => $arg) { + $queryArgs = $queryArgs->withArg(self::ALIASES[$key] ?? $key, $arg); + } + + $queryArgs = $this->applyOrderBy($criteria, $queryArgs); + $queryArgs = $this->translateOrderBy($criteria, $queryArgs); + + // Apply filters + foreach ($criteria->filters() as $filter) { + $queryArgs = $this->applyFilter($filter, $queryArgs, $criteria->languageCode()); + } + + if (count($criteria->hisCodes()) > 0) { + $queryArgs = $this->applyHisCodes($criteria->hisCodes(), $queryArgs); + } + + return $queryArgs; + } + + /** + * @param array $hisCodes + */ + public function applyHisCodes(array $hisCodes, WpQueryArgs $queryArgs): WpQueryArgs + { + $hisCodesQuery = []; + + foreach ($hisCodes as $hisCode) { + $taxQueryItem = [ + 'relation' => 'AND', + ]; + + try { + $taxonomyToTermMapping = $this->campoKeysRepository->taxonomyToTermsMapFromCampoKeys( + CampoKeys::fromHisCode($hisCode) + ); + } catch (RuntimeException) { + continue; + } + + if (count($taxonomyToTermMapping) === 0) { + continue; + } + + foreach ($taxonomyToTermMapping as $taxonomy => $termId) { + $taxQueryItem[] = [ + 'taxonomy' => $taxonomy, + 'terms' => [ + $termId, + ], + ]; + } + + $hisCodesQuery[] = $taxQueryItem; + } + + if (count($hisCodesQuery) === 0) { + return $queryArgs; + } + + $hisCodesQuery['relation'] = 'OR'; + + return $queryArgs->withTaxQueryItem($hisCodesQuery); + } + + private function applyOrderBy( + CollectionCriteria $criteria, + WpQueryArgs $queryArgs + ): WpQueryArgs { + + $orderBy = $criteria->args()['order_by'] ?? null; + if ($orderBy) { + // Order is defined explicitly + return $queryArgs; + } + + $currentTerm = $this->currentTerm($criteria); + $hasSearch = !empty($criteria->args()['search']); + $hasFilters = count($criteria->filters()) > 0; + $hasTerm = $currentTerm instanceof WP_Term; + if ($hasSearch || ($hasFilters && !$hasTerm)) { + // We can not detect current term + return $queryArgs->withOrderBy(self::DEFAULT_ORDER_BY); + } + + // No filters or single filter with detected term + $stickyKey = StickyDegreeProgramRepository::stickyKey($currentTerm); + return $queryArgs->withOrderBy(array_merge( + [$stickyKey => 'desc'], + self::DEFAULT_ORDER_BY, + )); + } + + private function translateOrderBy( + CollectionCriteria $criteria, + WpQueryArgs $queryArgs + ): WpQueryArgs { + + $languageCode = $criteria->languageCode() ?? MultilingualString::DE; + /** @var OrderBy | null $orderBy */ + $orderBy = $queryArgs->args()['orderby'] ?? null; + if (!$orderBy) { + return $queryArgs; + } + + $translatedOrderBy = []; + foreach ($orderBy as $property => $order) { + $key = $this->translateOrderByProperty($property, $languageCode); + $translatedOrderBy[$key] = $order; + } + + return $queryArgs->withOrderBy($translatedOrderBy); + } + + /** + * @psalm-param string $property + * @psalm-param LanguageCodes $languageCode + */ + private function translateOrderByProperty( + string $property, + string $languageCode, + ): string { + + if (!in_array($property, CollectionCriteria::SORTABLE_PROPERTIES, true)) { + return $property; + } + + if ( + $property === DegreeProgram::TITLE + && $languageCode === MultilingualString::DE + ) { + return $property; + } + + return implode('_', [$property, $languageCode]); + } + + private function applyFilter(Filter $filter, WpQueryArgs $queryArgs, ?string $languageCode = null): WpQueryArgs + { + return match (true) { + $this->isTaxonomyFilter($filter) => $this->applyTaxonomyFilter($filter, $queryArgs), + $filter instanceof SearchKeywordFilter => $this->applySearchFilter( + $filter, + $queryArgs, + $languageCode + ), + $filter instanceof AdmissionRequirementTypeFilter => $this->applyAdmissionRequirementFilter( + $filter, + $queryArgs, + $languageCode + ), + default => $queryArgs, + }; + } + + private function isTaxonomyFilter(Filter $filter): bool + { + return in_array(get_class($filter), self::TAXONOMY_BASED_FILTERS, true); + } + + private function applyAdmissionRequirementFilter( + AdmissionRequirementTypeFilter $filter, + WpQueryArgs $queryArgs, + ?string $languageCode = null + ): WpQueryArgs { + + $languageCode = $languageCode ?: MultilingualString::DE; + + return $queryArgs->withTaxQueryItem( + [ + 'relation' => 'OR', + [ + 'taxonomy' => BachelorOrTeachingDegreeAdmissionRequirementTaxonomy::KEY, + 'terms' => $filter->value(), + 'field' => 'slug', + 'compare' => 'IN', + 'include_children' => true, + ], + [ + 'taxonomy' => MasterDegreeAdmissionRequirementTaxonomy::KEY, + 'terms' => $filter->value(), + 'field' => 'slug', + 'compare' => 'IN', + 'include_children' => true, + ], + ] + ); + } + + private function applyTaxonomyFilter(Filter $filter, WpQueryArgs $queryArgs): WpQueryArgs + { + return $queryArgs->withTaxQueryItem( + [ + 'taxonomy' => $this->taxonomiesList->convertRestBaseToSlug($filter->id()), + 'terms' => (array) $filter->value(), + ] + ); + } + + private function applySearchFilter(SearchKeywordFilter $filter, WpQueryArgs $queryArgs, ?string $languageCode = null): WpQueryArgs + { + if (!$languageCode) { + return $queryArgs->withMetaQueryItem( + [ + 'relation' => 'OR', + [ + 'key' => 'fau_degree_program_searchable_content_' . MultilingualString::EN, + 'value' => $filter->value(), + 'compare' => 'LIKE', + ], + [ + 'key' => 'fau_degree_program_searchable_content_' . MultilingualString::DE, + 'value' => $filter->value(), + 'compare' => 'LIKE', + ], + ] + ); + } + + return $queryArgs->withMetaQueryItem( + [ + 'key' => 'fau_degree_program_searchable_content_' . $languageCode, + 'value' => $filter->value(), + 'compare' => 'LIKE', + ] + ); + } + + private function currentTerm(CollectionCriteria $criteria): ?WP_Term + { + if (count($criteria->filters()) !== 1) { + return null; + } + + $filter = $criteria->filters()[0]; + if (!$this->isTaxonomyFilter($filter)) { + return null; + } + + $values = $filter->value(); + if (!is_array($values) || count($values) !== 1) { + // Multiple terms are ignored + return null; + } + + $term = (int) $values[0]; + if (!$term) { + return null; + } + $taxonomy = $this->taxonomiesList->convertRestBaseToSlug($filter->id()); + if (!$taxonomy) { + return null; + } + $term = get_term($term, $taxonomy); + + return $term instanceof WP_Term ? $term : null; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryPaginationAwareCollection.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryPaginationAwareCollection.php new file mode 100644 index 000000000..d130f0949 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQueryPaginationAwareCollection.php @@ -0,0 +1,83 @@ + + * @template-implements PaginationAwareCollection + */ +final class WpQueryPaginationAwareCollection extends ArrayObject implements PaginationAwareCollection +{ + /** + * @param WP_Query $query WP_Query::get_posts() method must be run before + * to make pagination works properly + * @param T ...$items + */ + public function __construct( + private WP_Query $query, + DegreeProgramViewRaw | DegreeProgramViewTranslated ...$items + ) { + + parent::__construct($items); + } + + public function currentPage(): int + { + return (int) $this->query->get('paged', 1); + } + + public function nextPage(): ?int + { + if ($this->currentPage() >= $this->maxPages()) { + return null; + } + + return $this->currentPage() + 1; + } + + public function previousPage(): ?int + { + if ($this->currentPage() <= 1) { + return null; + } + + return min(($this->currentPage() - 1), $this->maxPages()); + } + + public function maxPages(): int + { + return (int) ceil($this->totalItems() / (int) $this->query->get('posts_per_page')); + } + + public function totalItems(): int + { + /** @var int|null $total */ + static $total; + + if (isset($total)) { + return $total; + } + + $total = $this->query->found_posts; + + if ($total < 1 && $this->currentPage() > 1) { + // Out-of-bounds, run the query again without LIMIT for total count. + $args = $this->query->query_vars; + unset($args['paged']); + $countQuery = new WP_Query(); + $countQuery->query($args); + $total = $countQuery->found_posts; + } + + return $total; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQuerySplitter.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQuerySplitter.php new file mode 100644 index 000000000..5f2ae4eb8 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Repository/WpQuerySplitter.php @@ -0,0 +1,49 @@ +hisCodes(); + + if (count($hisCodes) <= 1) { + return $criteria; + } + + $ids = []; + + foreach ($hisCodes as $hisCode) { + $criteria = $criteria->withHisCodes([$hisCode]); + $query = new WP_Query(); + /** @var array $ids */ + $ids = array_merge( + $query->query( + $this->queryArgsBuilder + ->build($criteria) + ->args() + ), + $ids + ); + } + + return $criteria + ->withHisCodes([]) + ->withInclude($ids); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/RestApi/TranslatedDegreeProgramController.php b/vendor/rrze/fau-studium-common/src/Infrastructure/RestApi/TranslatedDegreeProgramController.php new file mode 100644 index 000000000..52481449a --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/RestApi/TranslatedDegreeProgramController.php @@ -0,0 +1,691 @@ +namespace, '/' . $this->rest_base, [ + [ + 'methods' => WP_REST_Server::READABLE, + 'callback' => [$this, 'get_items'], + 'permission_callback' => [$this, 'get_items_permissions_check'], + 'args' => $this->get_collection_params(), + ], + ]); + register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', [ + [ + 'methods' => WP_REST_Server::READABLE, + 'callback' => [$this, 'get_item'], + 'permission_callback' => [$this, 'get_item_permissions_check'], + 'args' => [ + 'lang' => self::languageParam(), + ], + ], + ]); + register_rest_route($this->namespace, $this->rest_base . '/schema', [ + 'methods' => WP_REST_Server::READABLE, + 'callback' => [$this, 'get_public_item_schema'], + 'permission_callback' => static fn() => true, + ]); + } + + /** + * @param WP_REST_Request $request Full data about the request. + * + * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + public function get_items($request): WP_Error|WP_REST_Response + { + $criteria = CollectionCriteria::new() + ->withPage((int) $request->get_param('page')) + ->withPerPage((int) $request->get_param('per_page')) + ->addFilter( + new SearchKeywordFilter( + (string) $request->get_param('search') + ), + AdmissionRequirementTypeFilter::fromInput((array) $request->get_param(AdmissionRequirementTypeFilter::KEY)), + AreaOfStudyFilter::fromInput((array) $request->get_param(AreaOfStudyFilter::KEY)), + AttributeFilter::fromInput((array) $request->get_param(AttributeFilter::KEY)), + DegreeFilter::fromInput((array) $request->get_param(DegreeFilter::KEY)), + FacultyFilter::fromInput((array) $request->get_param(FacultyFilter::KEY)), + SemesterFilter::fromInput((array) $request->get_param(SemesterFilter::KEY)), + StudyLocationFilter::fromInput((array) $request->get_param(StudyLocationFilter::KEY)), + SubjectGroupFilter::fromInput((array) $request->get_param(SubjectGroupFilter::KEY)), + TeachingLanguageFilter::fromInput((array) $request->get_param(TeachingLanguageFilter::KEY)), + GermanLanguageSkillsForInternationalStudentsFilter::fromInput((array) $request->get_param(GermanLanguageSkillsForInternationalStudentsFilter::KEY)) + ) + ->withOrderBy([ + (string) $request->get_param('order_by') => + (string) $request->get_param('order') === 'asc' ? 'asc' : 'desc', + ]); + + $views = $this->degreeProgramCollectionRepository->findTranslatedCollection( + $criteria, + $this->requestedLanguage($request) + ); + + if (!$views instanceof PaginationAwareCollection) { + return new WP_Error( + 'unexpected_error', + _x( + 'Something went wrong. Please try again later.', + 'rest_api: response status', + 'fau-degree-program-common' + ), + ['status' => 500] + ); + } + + $data = []; + foreach ($views as $view) { + $data[] = $this->prepare_response_for_collection( + new WP_REST_Response($view->asArray()) + ); + } + + $response = new WP_REST_Response($data); + if ($views->totalItems() > 0 && $views->currentPage() > $views->maxPages()) { + return new WP_Error( + 'rest_post_invalid_page_number', + _x( + 'The page number requested is larger than the number of pages available.', + 'rest_api: response status', + 'fau-degree-program-common' + ), + ['status' => 400] + ); + } + $response->header('X-WP-Total', (string) $views->totalItems()); + $response->header('X-WP-TotalPages', (string) $views->maxPages()); + + $collectionUrl = rest_url($this->namespace . '/' . $this->rest_base); + $base = add_query_arg(urlencode_deep($request->get_query_params()), $collectionUrl); + + if ($views->previousPage() !== null) { + $response->link_header( + 'prev', + add_query_arg('page', $views->previousPage(), $base) + ); + } + + if ($views->nextPage() !== null) { + $response->link_header( + 'next', + add_query_arg('page', $views->nextPage(), $base) + ); + } + + return $response; + } + + /** + * @param WP_REST_Request $request Full data about the request. + */ + public function get_item($request): WP_Error|WP_REST_Response + { + /** @var WP_Post $post */ + $post = get_post((int)$request->get_param('id')); + $view = $this->prepare_item_for_response( + $post, + $request + ); + + if ($view instanceof DegreeProgramViewTranslated) { + return new WP_REST_Response($view->asArray()); + } + + return new WP_Error( + 'not_found', + _x( + 'Degree program not found.', + 'rest_api: response status', + 'fau-degree-program-common' + ), + ['status' => 404] + ); + } + + public function get_items_permissions_check($request): bool + { + return true; + } + + public function get_item_permissions_check($request): bool|WP_Error + { + $id = (int)$request->get_param('id'); + + $error = new WP_Error( + 'not_found', + _x( + 'Degree program not found.', + 'rest_api: response status', + 'fau-degree-program-common' + ), + ['status' => 404] + ); + + if ($id <= 0) { + return $error; + } + + $post = get_post($id); + if (!$post instanceof WP_Post) { + return $error; + } + + if ( + $post->post_type !== DegreeProgramPostType::KEY + || $post->post_status !== 'publish' + ) { + return $error; + } + + return true; + } + + /** + * @param WP_Post $item Post. + * @param WP_REST_Request $request Request object. + */ + public function prepare_item_for_response($item, $request): DegreeProgramViewTranslated|null + { + return $this->degreeProgramViewRepository->findTranslated( + DegreeProgramId::fromInt($item->ID), + $this->requestedLanguage($request), + ); + } + + /** + * @psalm-return 'de' | 'en' + */ + private function requestedLanguage(WP_REST_Request $request): string + { + $languageCode = (string) ($request->get_param('lang') ?? MultilingualString::DE); + + return in_array($languageCode, [MultilingualString::DE, MultilingualString::EN], true) + ? $languageCode + : MultilingualString::DE; + } + + /** + * @psalm-return array + */ + public function get_collection_params(): array + { + [ + 'page' => $page, + 'per_page' => $perPage, + 'search' => $search, + ] = parent::get_collection_params(); + + return [ + 'page' => $page, + 'per_page' => $perPage, + 'search' => $search, + 'lang' => self::languageParam(), + ]; + } + + private static function languageParam(): array + { + return [ + 'description' => _x( + 'Language code ("de" and "en" are supported).', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + 'default' => MultilingualString::DE, + ]; + } + + /** + * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong + */ + public function get_item_schema(): array + { + if (isset($this->schema)) { + return $this->schema; + } + + $this->schema = [ + DegreeProgram::ID => [ + 'description' => _x( + 'Unique identifier for the degree program.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'integer', + ], + DegreeProgram::FEATURED_IMAGE => [ + 'description' => _x( + 'Feature image.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::TEASER_IMAGE => [ + 'description' => _x( + 'Teaser image.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::TITLE => [ + 'description' => _x( + 'Title.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::SUBTITLE => [ + 'description' => _x( + 'Subtitle.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::STANDARD_DURATION => [ + 'description' => _x( + 'Standard duration of study.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::FEE_REQUIRED => [ + 'description' => _x( + 'Fee required.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'boolean', + ], + DegreeProgram::START => [ + 'description' => _x( + 'Start of degree program.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'array', + ], + DegreeProgram::NUMBER_OF_STUDENTS => [ + 'description' => _x( + 'Number of students.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::TEACHING_LANGUAGE => [ + 'description' => _x( + 'Teaching language.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::ATTRIBUTES => [ + 'description' => _x( + 'Attributes.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'array', + ], + DegreeProgram::DEGREE => [ + 'description' => _x( + 'Degree.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::FACULTY => [ + 'description' => _x( + 'Faculty.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'array', + ], + DegreeProgram::LOCATION => [ + 'description' => _x( + 'Study location.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'array', + ], + DegreeProgram::SUBJECT_GROUPS => [ + 'description' => _x( + 'Subject groups.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'array', + ], + DegreeProgram::VIDEOS => [ + 'description' => _x( + 'Videos.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'array', + ], + DegreeProgram::META_DESCRIPTION => [ + 'description' => _x( + 'Meta description.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::CONTENT => [ + 'description' => _x( + 'Content.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'array', + ], + DegreeProgramViewTranslated::ADMISSION_REQUIREMENT_LINK => [ + 'description' => _x( + 'Admission requirement link.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::ADMISSION_REQUIREMENTS => [ + 'description' => _x( + 'Admission requirements.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS => [ + 'description' => _x( + 'Content-related admission requirements for Master’s degree.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER => [ + 'description' => _x( + 'Application deadline winter semester.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER => [ + 'description' => _x( + 'Application deadline summer semester.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::DETAILS_AND_NOTES => [ + 'description' => _x( + 'Details and notes.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::LANGUAGE_SKILLS => [ + 'description' => _x( + 'Language skills.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY => [ + 'description' => _x( + 'Language skills for Faculty of Humanities, Social Sciences, and Theology only.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS => + [ + 'description' => _x( + 'Language certificates/German language skills for international applicants.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::START_OF_SEMESTER => [ + 'description' => _x( + 'Start of semester.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::SEMESTER_DATES => [ + 'description' => _x( + 'Semester dates.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::EXAMINATIONS_OFFICE => [ + 'description' => _x( + 'Examinations Office.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::EXAMINATION_REGULATIONS => [ + 'description' => _x( + 'Degree program and examination regulations.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::MODULE_HANDBOOK => [ + 'description' => _x( + 'Module handbook.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::URL => [ + 'description' => _x( + 'Degree program URL.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::DEPARTMENT => [ + 'description' => _x( + 'Department.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::STUDENT_ADVICE => [ + 'description' => _x( + 'Student Advice and Career Service.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::SUBJECT_SPECIFIC_ADVICE => [ + 'description' => _x( + 'Subject-specific advice.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::SERVICE_CENTERS => [ + 'description' => _x( + 'Counseling and Service Centers at FAU.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::INFO_BROCHURE => [ + 'description' => _x( + 'Info brochure degree program.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::SEMESTER_FEE => [ + 'description' => _x( + 'Semester fee.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::DEGREE_PROGRAM_FEES => [ + 'description' => _x( + 'Degree program fees.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'string', + ], + DegreeProgram::ABROAD_OPPORTUNITIES => [ + 'description' => _x( + 'Opportunities for spending time abroad.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::COMBINATIONS => [ + 'description' => _x( + 'Degree program possible combinations.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'array', + ], + DegreeProgram::LIMITED_COMBINATIONS => [ + 'description' => _x( + 'Degree program limited possible combinations.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'array', + ], + DegreeProgramViewTranslated::TRANSLATIONS => [ + 'description' => _x( + 'Available translations.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS => [ + 'description' => _x( + 'Notes for international applicants.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::STUDENT_INITIATIVES => [ + 'description' => _x( + 'Students\' Union/Student Initiatives.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + DegreeProgram::CAMPO_KEYS => [ + 'description' => _x( + 'Degree program Campo Keys.', + 'rest_api: schema item description', + 'fau-degree-program-common' + ), + 'type' => 'object', + ], + ]; + + return $this->schema; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Sanitizer/HtmlDegreeProgramSanitizer.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Sanitizer/HtmlDegreeProgramSanitizer.php new file mode 100644 index 000000000..edb54f466 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Sanitizer/HtmlDegreeProgramSanitizer.php @@ -0,0 +1,81 @@ +stripNotAllowedShortcodes( + wp_kses( + $content, + self::ALLOWED_ENTITIES + ) + ); + } + + public function sanitizeTextField(string $text): string + { + return wp_strip_all_tags($text); + } + + public function sanitizeMultiLingualTextField(MultilingualString $text): MultilingualString + { + return MultilingualString::fromTranslations( + $text->id(), + wp_strip_all_tags($text->inGerman()), + wp_strip_all_tags($text->inEnglish()), + ); + } + + public function sanitizeUrlField(string $url): string + { + return filter_var($url, FILTER_VALIDATE_URL) ?: ''; + } + + public function sanitizeMultilingualUrlField(MultilingualString $multilingualUrl): MultilingualString + { + return MultilingualString::fromTranslations( + $multilingualUrl->id(), + $this->sanitizeUrlField($multilingualUrl->inGerman()), + $this->sanitizeUrlField($multilingualUrl->inEnglish()), + ); + } + + private function stripNotAllowedShortcodes(string $content, ?array $allowedShortcodes = null): string + { + if (!str_contains($content, '[')) { + return $content; + } + + preg_match_all( + '/' . get_shortcode_regex() . '/', + $content, + $matches, + PREG_SET_ORDER + ); + + if (!$matches) { + return $content; + } + + /** + * @see https://developer.wordpress.org/reference/functions/get_shortcode_regex/ + * @var array $shortcode + */ + foreach ($matches as $shortcode) { + $fullShortcodeTag = (string) $shortcode[0]; + $shortcodeTagName = (string) $shortcode[2]; + if (!in_array($shortcodeTagName, $allowedShortcodes ?? self::ALLOWED_SHORTCODES, true)) { + $content = str_replace($fullShortcodeTag, '', $content); + } + } + + return $content; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Sanitizer/SerializedBlocksDegreeProgramSanitizer.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Sanitizer/SerializedBlocksDegreeProgramSanitizer.php new file mode 100644 index 000000000..351da1fd9 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Sanitizer/SerializedBlocksDegreeProgramSanitizer.php @@ -0,0 +1,68 @@ +, + * innerHTML: string + * } + */ +final class SerializedBlocksDegreeProgramSanitizer implements DegreeProgramSanitizer +{ + public function sanitizeContentField(string $content): string + { + if (!has_blocks($content)) { + return $content; + } + + /** @psalm-var array $parsedBlocks */ + $parsedBlocks = parse_blocks($content); + $result = ''; + foreach ($parsedBlocks as $block) { + $result .= $this->isValidBlock($block) ? serialize_block($block) : ''; + } + + $filteredContent = trim((string) apply_filters('the_content', $result)); + if (!$filteredContent) { + return ''; + } + + return $result; + } + + /** + * @psalm-param ParsedBlock $block + */ + private function isValidBlock(array $block): bool + { + if (!in_array($block['blockName'], self::ALLOWED_BLOCKS, true)) { + return false; + } + + return match ($block['blockName']) { + 'core/heading' => in_array((int) ($block['attrs']['level'] ?? 2), [3, 4, 5], true), + 'core/shortcode' => (bool) preg_match( + $this->allowedShortcodeRegexpPattern(), + trim($block['innerHTML']) + ), + default => true, + }; + } + + /** + * @return non-empty-string + */ + private function allowedShortcodeRegexpPattern(): string + { + return sprintf( + '#^\[(%s)#', + implode('|', array_map('preg_quote', self::ALLOWED_SHORTCODES)) + ); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/DirectoryLocator.php b/vendor/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/DirectoryLocator.php new file mode 100644 index 000000000..fc5bf5950 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/DirectoryLocator.php @@ -0,0 +1,92 @@ + */ + private array $directories = []; + + /** @var array */ + private array $cachedPaths = []; + + private function __construct(string ...$directories) + { + $this->directories = $directories; + } + + public static function new(string ...$directories): self + { + return new self(...$directories); + } + + public function locate(string $templateName): string + { + $resolvedPath = $this->resolvePath($templateName); + + if ($resolvedPath !== null) { + return $resolvedPath; + } + + throw new UnexpectedValueException( + sprintf( + 'Could not find template "%s".', + $templateName, + ) + ); + } + + private function resolvePath(string $templateName): ?string + { + $normalizedTemplateName = wp_normalize_path($templateName); + + if (array_key_exists($normalizedTemplateName, $this->cachedPaths)) { + return $this->cachedPaths[$normalizedTemplateName]; + } + + $templateFile = $this->maybeAddExtension($normalizedTemplateName); + + if (count($this->directories) === 0) { + // If no directory is registered, we expect `locate()` to receive an absolute path + $this->directories = ['/']; + } + + foreach ($this->directories as $directory) { + $path = wp_normalize_path($directory . '/' . $templateFile); + + if (self::isValidFile($path)) { + $this->cachedPaths[$normalizedTemplateName] = $path; + return $this->cachedPaths[$normalizedTemplateName]; + } + } + + $this->cachedPaths[$normalizedTemplateName] = null; + return null; + } + + private function maybeAddExtension(string $templateName): string + { + return str_ends_with($templateName, '.php') + ? $templateName + : $templateName . '.php'; + } + + private static function isValidFile(string $path): bool + { + if (!$path) { + return false; + } + + /** @var array $files */ + static $files = []; + if (!isset($files[$path])) { + $files[$path] = is_file($path) && is_readable($path); + } + + return $files[$path]; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/Locator.php b/vendor/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/Locator.php new file mode 100644 index 000000000..ea5479705 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/TemplateRenderer/Locator.php @@ -0,0 +1,14 @@ +locator = $locator; + } + + public static function new( + Locator $locator, + ): self { + + return new self($locator); + } + + public function render(string $templateName, array $data = []): string + { + $level = ob_get_level(); + /** @psalm-suppress TypeDoesNotContainType */ + $isDebug = defined('WP_DEBUG') && WP_DEBUG; + + try { + $fullPath = $this->locator->locate($templateName); + + ob_start(); + + // phpcs:disable Inpsyde.CodeQuality.VariablesName.SnakeCaseVar + /** @psalm-suppress UnusedClosureParam */ + (static function (string $__fullPath__, array $data, Renderer $renderer): void { + /** @psalm-suppress UnresolvableInclude */ + include $__fullPath__; + })($fullPath, $data, $this); + // phpcs:enable Inpsyde.CodeQuality.VariablesName.SnakeCaseVar + + + return ob_get_clean() ?: ''; + } catch (Throwable $throwable) { + while (ob_get_level() > $level) { + ob_end_clean(); + } + + if (!$isDebug) { + return ''; + } + + throw new RuntimeException( + sprintf('Could not render template %s', $templateName), + 0, + $throwable + ); + } + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Validator/CompositeValidator.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Validator/CompositeValidator.php new file mode 100644 index 000000000..7bc97989d --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Validator/CompositeValidator.php @@ -0,0 +1,39 @@ + */ + private array $validators; + + public function __construct(DegreeProgramDataValidator ...$validators) + { + $this->validators = $validators; + } + + public function validatePublish(array $data): Violations + { + $violations = Violations::new(); + foreach ($this->validators as $validator) { + $violations->add(...$validator->validatePublish($data)); + } + + return $violations; + } + + public function validateDraft(array $data): Violations + { + $violations = Violations::new(); + foreach ($this->validators as $validator) { + $violations->add(...$validator->validateDraft($data)); + } + + return $violations; + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Validator/ConditionalFieldsValidator.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Validator/ConditionalFieldsValidator.php new file mode 100644 index 000000000..dcf7ed212 --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Validator/ConditionalFieldsValidator.php @@ -0,0 +1,119 @@ +isFeeRequired()) { + $violations->add( + ...self::validateRequiredMultilingualString( + $raw->degreeProgramFees(), + DegreeProgram::DEGREE_PROGRAM_FEES + ) + ); + } + + if (ConditionalFieldsFilter::isMasterContext($raw->degree())) { + !$raw->admissionRequirements()->master()->isEmpty() + or $violations->add(self::makeEmptyFieldViolation( + DegreeProgram::ADMISSION_REQUIREMENTS, + AdmissionRequirements::MASTER + )); + + $violations->add( + ...self::validateRequiredMultilingualString( + $raw->contentRelatedMasterRequirements(), + DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS + ) + ); + } + + if ( + ConditionalFieldsFilter::isBachelorOrTeachingDegreeContext($raw->degree()) + && !ConditionalFieldsFilter::isAdditionalDegree($raw->degree()) + ) { + !$raw->admissionRequirements()->bachelorOrTeachingDegree()->isEmpty() + or $violations->add(self::makeEmptyFieldViolation( + DegreeProgram::ADMISSION_REQUIREMENTS, + AdmissionRequirements::BACHELOR_OR_TEACHING_DEGREE + )); + + ($raw->admissionRequirements() + ->bachelorOrTeachingDegree() + ->hasGermanName(ConditionalFieldsFilter::ADMISSION_REQUIREMENT_FREE) + || !$raw->admissionRequirements()->teachingDegreeHigherSemester()->isEmpty()) + or $violations->add(self::makeEmptyFieldViolation( + DegreeProgram::ADMISSION_REQUIREMENTS, + AdmissionRequirements::TEACHING_DEGREE_HIGHER_SEMESTER + )); + } + + return $violations; + } + + private static function makeEmptyFieldViolation(string $root, string $path = ''): Violation + { + $paths = [$root]; + if ($path) { + $paths[] = $path; + } + + return Violation::new( + implode('.', $paths), + _x( + 'This field can not be empty.', + 'backoffice: REST API error message', + 'fau-degree-program-common' + ), + 'rest_too_short' + ); + } + + private static function validateRequiredMultilingualString( + MultilingualString $multilingualString, + string $root + ): Violations { + + $violations = Violations::new(); + $multilingualString->inGerman() + or $violations->add(self::makeEmptyFieldViolation($root, MultilingualString::DE)); + $multilingualString->inEnglish() + or $violations->add(self::makeEmptyFieldViolation($root, MultilingualString::EN)); + + return $violations; + } + + public function validateDraft(array $data): Violations + { + return Violations::new(); + } +} diff --git a/vendor/rrze/fau-studium-common/src/Infrastructure/Validator/JsonSchemaDegreeProgramDataValidator.php b/vendor/rrze/fau-studium-common/src/Infrastructure/Validator/JsonSchemaDegreeProgramDataValidator.php new file mode 100644 index 000000000..83f2a0f4e --- /dev/null +++ b/vendor/rrze/fau-studium-common/src/Infrastructure/Validator/JsonSchemaDegreeProgramDataValidator.php @@ -0,0 +1,216 @@ + 'array', + 'items' => [ + 'type' => 'integer', + 'minimum' => 0, + ], + ]; + + public const DEADLINE_PATTERN = '^((0[1-9]|[12][0-9]|3[01])\.(0[13578]|1[02])|(0[1-9]|[12][0-9]|30)\.(0[469]|11)|(0[1-9]|1[0-9]|2[0-8])\.02)\.$|^$'; + + public const REQUIRED_PROPERTIES = [ + DegreeProgram::ID, + DegreeProgram::SLUG, + DegreeProgram::FEATURED_IMAGE, + DegreeProgram::TEASER_IMAGE, + DegreeProgram::TITLE, + DegreeProgram::SUBTITLE, + DegreeProgram::STANDARD_DURATION, + DegreeProgram::FEE_REQUIRED, + DegreeProgram::START, + DegreeProgram::NUMBER_OF_STUDENTS, + DegreeProgram::TEACHING_LANGUAGE, + DegreeProgram::ATTRIBUTES, + DegreeProgram::DEGREE, + DegreeProgram::FACULTY, + DegreeProgram::LOCATION, + DegreeProgram::SUBJECT_GROUPS, + DegreeProgram::VIDEOS, + DegreeProgram::META_DESCRIPTION, + DegreeProgram::CONTENT, + DegreeProgram::ADMISSION_REQUIREMENTS, + DegreeProgram::CONTENT_RELATED_MASTER_REQUIREMENTS, + DegreeProgram::APPLICATION_DEADLINE_WINTER_SEMESTER, + DegreeProgram::APPLICATION_DEADLINE_SUMMER_SEMESTER, + DegreeProgram::DETAILS_AND_NOTES, + DegreeProgram::LANGUAGE_SKILLS, + DegreeProgram::LANGUAGE_SKILLS_HUMANITIES_FACULTY, + DegreeProgram::GERMAN_LANGUAGE_SKILLS_FOR_INTERNATIONAL_STUDENTS, + DegreeProgram::START_OF_SEMESTER, + DegreeProgram::SEMESTER_DATES, + DegreeProgram::EXAMINATIONS_OFFICE, + DegreeProgram::EXAMINATION_REGULATIONS, + DegreeProgram::MODULE_HANDBOOK, + DegreeProgram::URL, + DegreeProgram::DEPARTMENT, + DegreeProgram::STUDENT_ADVICE, + DegreeProgram::SUBJECT_SPECIFIC_ADVICE, + DegreeProgram::SERVICE_CENTERS, + DegreeProgram::INFO_BROCHURE, + DegreeProgram::SEMESTER_FEE, + DegreeProgram::DEGREE_PROGRAM_FEES, + DegreeProgram::ABROAD_OPPORTUNITIES, + DegreeProgram::KEYWORDS, + DegreeProgram::AREA_OF_STUDY, + DegreeProgram::COMBINATIONS, + DegreeProgram::LIMITED_COMBINATIONS, + DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS, + DegreeProgram::APPLY_NOW_LINK, + DegreeProgram::CAMPO_KEYS, + ]; + + /** + * @psalm-param SchemaType $draftSchema + * @psalm-param SchemaType $publishSchema + */ + public function __construct( + private array $draftSchema, + private array $publishSchema, + private SerializedBlocksDegreeProgramSanitizer $blocksSanitizer, + ) { + } + + public function validatePublish(array $data): Violations + { + return $this->validate($data, $this->publishSchema); + } + + public function validateDraft(array $data): Violations + { + return $this->validate($data, $this->draftSchema); + } + + /** + * @param array $data + * @psalm-param SchemaType $schema + */ + private function validate(array $data, array $schema): Violations + { + $violations = Violations::new(); + + // It's important to sanitize content fields before validation to clear fields + // with empty paragraphs only. + array_walk_recursive( + $data, + function (mixed &$value) { + $value = is_string($value) + ? $this->blocksSanitizer->sanitizeContentField($value) + : $value; + } + ); + /** @psalm-var array $data */ + + $generalResult = rest_validate_value_from_schema( + $data, + $schema, + 'degree_program', + ); + + if (!$generalResult instanceof WP_Error) { + return $violations; + } + + // Find missing required properties violations + if ($generalResult->get_error_code() === 'rest_property_required') { + $violations->offsetSet( + 'degree_program', + Violation::new( + 'degree_program', + $generalResult->get_error_message(), + (string) $generalResult->get_error_code(), + ) + ); + } + + // Go through each property recursively and populate rest of violations. + $this->populateViolations( + $data, + $schema['properties'], + $violations, + ); + + return $violations; + } + + /** + * @param array $fields + * @param array $schema + */ + private function populateViolations( + mixed $fields, + array $schema, + Violations $violations, + string $prefixKey = '', + ): void { + + foreach ($fields as $key => $field) { + /** @var array{properties: array[], type: string} $fieldSchema */ + $fieldSchema = $schema[$key]; + + $path = $prefixKey ? $prefixKey . '.' . $key : $key; + + $error = rest_validate_value_from_schema( + $field, + $fieldSchema, + $path, + ); + + if (!$error instanceof WP_Error) { + continue; + } + + if ( + $fieldSchema['type'] === 'object' + && isset($fieldSchema['properties']) + && $fieldSchema['properties'] + && is_array($field) + ) { + /** @var array $field */ + $this->populateViolations($field, $fieldSchema['properties'], $violations, $path); + continue; + } + + /** @var string $errorCode */ + $errorCode = $error->get_error_code(); + + $violations->offsetSet( + $path, + Violation::new( + $path, + $error->get_error_message(), + $errorCode, + ) + ); + } + } + + public function publishSchema(): array + { + return $this->publishSchema; + } + + public function draftSchema(): array + { + return $this->draftSchema; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/bootstrap.php b/vendor/rrze/fau-studium-common/tests/bootstrap.php new file mode 100644 index 000000000..c40fca314 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/bootstrap.php @@ -0,0 +1,13 @@ +fixtureData(); + $sut = new ConditionalFieldsValidator( + new FacultyRepository(), + ); + $result = $sut->validatePublish($data); + $this->assertSame($result->count(), 0); + } + + public function testEmptyDegreeProgramFees(): void + { + $data = $this->fixtureData(); + $data[DegreeProgram::DEGREE_PROGRAM_FEES] = MultilingualString::empty()->asArray(); + $sut = new ConditionalFieldsValidator( + new FacultyRepository(), + ); + $violations = $sut->validatePublish($data); + $this->assertSame($violations->count(), 2); + $this->assertSame([ + 'degree_program_fees.de' => [ + 'path' => 'degree_program_fees.de', + 'errorMessage' => 'This field can not be empty.', + 'errorCode' => 'rest_too_short', + ], + 'degree_program_fees.en' => [ + 'path' => 'degree_program_fees.en', + 'errorMessage' => 'This field can not be empty.', + 'errorCode' => 'rest_too_short', + ], + ], $violations->asArray()); + } + + public function testEmptyMasterAdmissionRequirement(): void + { + $data = $this->fixtureData(); + $data[DegreeProgram::DEGREE][Degree::ABBREVIATION][MultilingualString::DE] = 'MA'; + $data[DegreeProgram::ADMISSION_REQUIREMENTS][AdmissionRequirements::MASTER] = AdmissionRequirement::empty()->asArray(); + $sut = new ConditionalFieldsValidator( + new FacultyRepository(), + ); + $violations = $sut->validatePublish($data); + $this->assertSame($violations->count(), 1); + $this->assertSame([ + 'admission_requirements.master' => [ + 'path' => 'admission_requirements.master', + 'errorMessage' => 'This field can not be empty.', + 'errorCode' => 'rest_too_short', + ], + ], $violations->asArray()); + } + + public function testSkipValidationOnAdditionalDegree(): void + { + $data = $this->fixtureData(); + $data[DegreeProgram::DEGREE][Degree::NAME][MultilingualString::DE] = 'Weiteres'; + $data[DegreeProgram::ADMISSION_REQUIREMENTS][AdmissionRequirements::BACHELOR_OR_TEACHING_DEGREE] = AdmissionRequirement::empty()->asArray(); + $sut = new ConditionalFieldsValidator( + new FacultyRepository(), + ); + $violations = $sut->validatePublish($data); + $this->assertSame($violations->count(), 0); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/functional/Logger/WordPressLoggerTest.php b/vendor/rrze/fau-studium-common/tests/functional/Logger/WordPressLoggerTest.php new file mode 100644 index 000000000..f9ecda61b --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/functional/Logger/WordPressLoggerTest.php @@ -0,0 +1,106 @@ +tmpStream = tmpfile(); + $this->oldErrorLogValue = ini_set( + 'error_log', + stream_get_meta_data($this->tmpStream)['uri'] + ); + define('WP_DEBUG_LOG', true); + parent::setUp(); + + $this->wpOption->addOption('home', 'https://fau.de'); + } + + public function tearDown(): void + { + ini_set('error_log', $this->oldErrorLogValue); + parent::tearDown(); + } + + public function testWordPressHook(): void + { + add_action('rrze.log.error', static function (string $message) { + self::assertSame('Error happens!', $message); + }); + + $sut = WordPressLogger::new(self::PACKAGE); + $sut->error('Error happens!'); + $sut->info('Some info.'); + self::assertSame(1, did_action('rrze.log.error')); + self::assertSame(1, did_action('rrze.log.info')); + } + + public function testLogEntry(): void + { + $sut = WordPressLogger::new(self::PACKAGE); + $sut->error('Error happens!'); + self::assertStringEndsWith( + "[ERROR] [my_package]: Error happens!\n{\"site_url\":\"https:\/\/fau.de\"}\n", + stream_get_contents($this->tmpStream) + ); + } + + /** + * phpcs:disable Inpsyde.CodeQuality.LineLength.TooLong + */ + public function testContext(): void + { + add_action('rrze.log.error', static function (string $message, array $context) { + self::assertSame('here', $context['where']); + self::assertSame(self::PACKAGE, $context['plugin']); + }, 10, 2); + + $sut = WordPressLogger::new(self::PACKAGE); + $sut->error('Error happens!', ['where' => 'here']); + self::assertStringEndsWith( + "[ERROR] [my_package]: Error happens!\n{\"where\":\"here\",\"site_url\":\"https:\/\/fau.de\"}\n", + stream_get_contents($this->tmpStream) + ); + } + + public function testException(): void + { + $exception = new Exception('Error!'); + + add_action('rrze.log.error', static function (string $message, array $context) { + self::assertSame('Error happens!', $message); + self::assertInstanceOf(Exception::class, $context['exception']); + self::assertSame('Error!', $context['exception']->getMessage()); + }, 10, 2); + + $sut = WordPressLogger::new(self::PACKAGE); + $sut->error('Error happens!', ['exception' => $exception]); + $entries = explode("\n", stream_get_contents($this->tmpStream)); + self::assertStringEndsWith( + "[ERROR] [my_package]: Error happens!", + $entries[0] + ); + self::assertStringEndsWith( + "Error!", + $entries[1] + ); + self::assertStringEndsWith( + "Fau\DegreeProgram\Common\Tests\Logger\WordPressLoggerTest->testException()", + $entries[2] + ); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/functional/Repository/IdGeneratorTest.php b/vendor/rrze/fau-studium-common/tests/functional/Repository/IdGeneratorTest.php new file mode 100644 index 000000000..0c813a05a --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/functional/Repository/IdGeneratorTest.php @@ -0,0 +1,175 @@ + 5]); + $sut = new IdGenerator(); + + $this->assertSame( + 'term:5', + $sut->generateTermId($term) + ); + $this->assertSame( + 'term:5:name', + $sut->generateTermId($term, 'name') + ); + $this->assertSame( + 'term_meta:5:abbreviation', + $sut->generateTermMetaId($term, 'abbreviation') + ); + } + + public function testGenerateIdsForPost(): void + { + $post = new WP_Post((object) ['ID' => 5]); + $sut = new IdGenerator(); + + $this->assertSame( + 'post:5', + $sut->generatePostId($post) + ); + $this->assertSame( + 'post:5:title', + $sut->generatePostId($post, 'title') + ); + $this->assertSame( + 'post_meta:5:meta_description', + $sut->generatePostMetaId($post, 'meta_description') + ); + } + + public function testGenerateIdsForOption(): void + { + $optionKey = 'fau_start_of_semester'; + $sut = new IdGenerator(); + + $this->assertSame( + 'option:fau_start_of_semester', + $sut->generateOptionId($optionKey) + ); + $this->assertSame( + 'option:fau_start_of_semester:link_text', + $sut->generateOptionId($optionKey, 'link_text') + ); + } + + public function testParseId(): void + { + $sut = new IdGenerator(); + [ + 'type' => $type, + 'entityId' => $parsedPostId, + 'subField' => $key, + ] = $sut->parseId('post:5'); + $this->assertSame('post', $type); + $this->assertSame('5', $parsedPostId); + $this->assertNull($key); + + [ + 'type' => $type, + 'entityId' => $parsedPostId, + 'subField' => $key, + ] = $sut->parseId('post_meta:5:meta_description'); + $this->assertSame('post_meta', $type); + $this->assertSame('5', $parsedPostId); + $this->assertSame('meta_description', $key); + } + + /** + * @dataProvider termListIdsProvider + */ + public function testTermListIds( + MultilingualString|MultilingualList|MultilingualLink|MultilingualLinks|NumberOfStudents|Degree $valueObject, + array $ids + ): void { + + $sut = new IdGenerator(); + $this->assertSame($ids, $sut->termIdsList($valueObject)); + } + + public function termListIdsProvider(): iterable + { + yield 'multilingual_string' => [ + MultilingualString::fromTranslations('term:25:name', '', ''), + [25], + ]; + + yield 'multilingual_list' => [ + MultilingualList::new( + MultilingualString::fromTranslations('term:25:name', '', ''), + MultilingualString::fromTranslations('term:26:name', '', ''), + ), + [25, 26], + ]; + + yield 'multilingual_link' => [ + MultilingualLink::new( + 'term:25', + MultilingualString::fromTranslations('term:25:name', '', ''), + MultilingualString::fromTranslations('term_meta:25:link_text', '', ''), + MultilingualString::fromTranslations('term_meta:25:link_url', '', ''), + ), + [25], + ]; + + yield 'multilingual_links' => [ + MultilingualLinks::new( + MultilingualLink::new( + 'term:25', + MultilingualString::fromTranslations('term:25:name', '', ''), + MultilingualString::fromTranslations('term_meta:25:link_text', '', ''), + MultilingualString::fromTranslations('term_meta:25:link_url', '', ''), + ), + MultilingualLink::new( + 'term:27', + MultilingualString::fromTranslations('term:27:name', '', ''), + MultilingualString::fromTranslations('term_meta:27:link_text', '', ''), + MultilingualString::fromTranslations('term_meta:27:link_url', '', ''), + ), + ), + [25, 27], + ]; + + yield 'number_of_students' => [ + NumberOfStudents::new('term:25', '>10', ''), + [25], + ]; + + yield 'degree' => [ + Degree::new( + 'term:25', + MultilingualString::fromTranslations('term:25:name', '', ''), + MultilingualString::fromTranslations('term_meta:25:name', '', ''), + null + ), + [25], + ]; + } + + public function testTermListIdsForPostMeta(): void + { + $this->expectException(RuntimeException::class); + $sut = new IdGenerator(); + $sut->termIdsList( + MultilingualString::fromTranslations('post_meta:25:description', '', '') + ); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/functional/Repository/WpQueryPaginationAwareCollectionTest.php b/vendor/rrze/fau-studium-common/tests/functional/Repository/WpQueryPaginationAwareCollectionTest.php new file mode 100644 index 000000000..d60a024d4 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/functional/Repository/WpQueryPaginationAwareCollectionTest.php @@ -0,0 +1,79 @@ +init(); + $query->posts = [1, 2, 3, 4, 5]; + $query->found_posts = 51; + $query->set('paged', 2); + $query->set('posts_per_page', 5); + + $sut = new WpQueryPaginationAwareCollection($query); + $this->assertSame(2, $sut->currentPage()); + $this->assertSame(3, $sut->nextPage()); + $this->assertSame(1, $sut->previousPage()); + $this->assertSame(11, $sut->maxPages()); + $this->assertSame(51, $sut->totalItems()); + } + + public function testFirstPage(): void + { + $query = new WP_Query(); + $query->init(); + $query->posts = [1, 2, 3, 4, 5]; + $query->found_posts = 51; + $query->set('posts_per_page', 5); + + $sut = new WpQueryPaginationAwareCollection($query); + $this->assertSame(1, $sut->currentPage()); + $this->assertSame(2, $sut->nextPage()); + $this->assertNull($sut->previousPage()); + $this->assertSame(11, $sut->maxPages()); + $this->assertSame(51, $sut->totalItems()); + } + + public function testLastPage(): void + { + $query = new WP_Query(); + $query->init(); + $query->posts = [1, 2, 3, 4, 5]; + $query->found_posts = 51; + $query->set('paged', 11); + $query->set('posts_per_page', 5); + + $sut = new WpQueryPaginationAwareCollection($query); + $this->assertSame(11, $sut->currentPage()); + $this->assertNull($sut->nextPage()); + $this->assertSame(10, $sut->previousPage()); + $this->assertSame(11, $sut->maxPages()); + $this->assertSame(51, $sut->totalItems()); + } + + public function testInvalid(): void + { + $query = new WP_Query(); + $query->init(); + $query->posts = []; + $query->found_posts = 51; + $query->set('paged', 15); + $query->set('posts_per_page', 5); + + $sut = new WpQueryPaginationAwareCollection($query); + $this->assertSame(15, $sut->currentPage()); + $this->assertNull($sut->nextPage()); + $this->assertSame(11, $sut->previousPage()); + $this->assertSame(11, $sut->maxPages()); + $this->assertSame(51, $sut->totalItems()); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/functional/Sanitizer/HtmlDegreeProgramSanitizerTest.php b/vendor/rrze/fau-studium-common/tests/functional/Sanitizer/HtmlDegreeProgramSanitizerTest.php new file mode 100644 index 000000000..8456c67b4 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/functional/Sanitizer/HtmlDegreeProgramSanitizerTest.php @@ -0,0 +1,39 @@ + ''); + add_shortcode('wrong_shortcode', static fn() => ''); + + $sut = new HtmlDegreeProgramSanitizer(); + + $this->assertHtmlEqual($output, $sut->sanitizeContentField($input)); + } + + public function serializedBlocksDataProvider(): iterable + { + $input = (string) file_get_contents( + RESOURCES_DIR . '/fixtures/content_field_html_input.html' + ); + $output = (string) file_get_contents( + RESOURCES_DIR . '/fixtures/content_field_html_output.html' + ); + + yield 'basic_data' => [$input, $output]; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/functional/Sanitizer/SerializedBlocksDegreeProgramSanitizerTest.php b/vendor/rrze/fau-studium-common/tests/functional/Sanitizer/SerializedBlocksDegreeProgramSanitizerTest.php new file mode 100644 index 000000000..aac817778 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/functional/Sanitizer/SerializedBlocksDegreeProgramSanitizerTest.php @@ -0,0 +1,35 @@ +assertHtmlEqual($output, $sut->sanitizeContentField($input)); + } + + public function serializedBlocksDataProvider(): iterable + { + $input = (string) file_get_contents( + RESOURCES_DIR . '/fixtures/content_field_serialized_blocks_input.html' + ); + $output = (string) file_get_contents( + RESOURCES_DIR . '/fixtures/content_field_serialized_blocks_output.html' + ); + + yield 'basic_data' => [$input, $output]; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/functional/TemplateRenderer/BasicRenderingDebugModeTest.php b/vendor/rrze/fau-studium-common/tests/functional/TemplateRenderer/BasicRenderingDebugModeTest.php new file mode 100644 index 000000000..41d675c7a --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/functional/TemplateRenderer/BasicRenderingDebugModeTest.php @@ -0,0 +1,61 @@ +assertSame( + 'Hello World!', + $this->sut->render('hello.php', ['hello' => 'Hello World!']) + ); + } + + public function testWithoutExtension(): void + { + $this->assertSame( + 'Hello World!', + $this->sut->render('hello', ['hello' => 'Hello World!']) + ); + } + + public function testNonExistingTemplateName(): void + { + $exceptionHasBeenCaught = false; + + try { + $this->sut->render('wrong_name.php'); + } catch (Throwable $throwable) { + $exceptionHasBeenCaught = true; + $this->assertInstanceOf(RuntimeException::class, $throwable); + + /** @var Throwable $previous */ + $previous = $throwable->getPrevious(); + $this->assertInstanceOf(UnexpectedValueException::class, $previous); + $this->assertStringContainsString('wrong_name.php', $previous->getMessage()); + } finally { + $this->assertTrue($exceptionHasBeenCaught); + } + } + + public function testNonExistingVariables(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/hello\.php/'); + $this->sut->render('hello.php'); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/functional/TemplateRenderer/BasicRenderingTest.php b/vendor/rrze/fau-studium-common/tests/functional/TemplateRenderer/BasicRenderingTest.php new file mode 100644 index 000000000..056fcd172 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/functional/TemplateRenderer/BasicRenderingTest.php @@ -0,0 +1,18 @@ +assertSame( + '', + $this->sut->render('wrong', ['hello' => 'Hello World!']) + ); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/functional/TemplateRenderer/NestedRenderingTest.php b/vendor/rrze/fau-studium-common/tests/functional/TemplateRenderer/NestedRenderingTest.php new file mode 100644 index 000000000..50a51c179 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/functional/TemplateRenderer/NestedRenderingTest.php @@ -0,0 +1,26 @@ +assertHtmlEqual( + '', + $this->sut->render('list.php', ['list' => $this->prepareList()]) + ); + } + + private function prepareList(): ListDto + { + $listItem = new ListItemDto('https://google.com', 'Google'); + return new ListDto('Search Engines', $listItem); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/functional/Validator/JsonSchemaDegreeProgramDataValidatorTest.php b/vendor/rrze/fau-studium-common/tests/functional/Validator/JsonSchemaDegreeProgramDataValidatorTest.php new file mode 100644 index 000000000..757d2a911 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/functional/Validator/JsonSchemaDegreeProgramDataValidatorTest.php @@ -0,0 +1,105 @@ +sut = new JsonSchemaDegreeProgramDataValidator( + require ROOT_DIR . '/config/schema_draft.php', + require ROOT_DIR . '/config/schema_publish.php', + new SerializedBlocksDegreeProgramSanitizer(), + ); + + parent::setUp(); + } + + /** + * @dataProvider fixtureDataProvider + */ + public function testSuccessfulValidation(array $fixtureData): void + { + $violations = $this->sut->validatePublish($fixtureData); + $this->assertCount(0, $violations->getArrayCopy()); + $violations = $this->sut->validateDraft($fixtureData); + $this->assertCount(0, $violations->getArrayCopy()); + } + + /** + * @dataProvider fixtureDataProvider + */ + public function testViolations(array $fixtureData): void + { + unset($fixtureData['content']); + $violations = $this->sut->validateDraft($fixtureData); + $this->assertCount(1, $violations->getArrayCopy()); + $this->assertSame( + 'content is a required property of degree_program.', + $violations['degree_program']->errorMessage() + ); + } + + /** + * @dataProvider invalidDeadlineDataProvider + */ + public function testInvalidApplicationDeadlines(string $deadline): void + { + $fixtureData = $this->fixtureData(); + $fixtureData['application_deadline_winter_semester'] = $deadline; + + $violations = $this->sut->validatePublish($fixtureData); + $this->assertCount(1, $violations->getArrayCopy()); + $this->assertStringStartsWith( + 'application_deadline_winter_semester does not match pattern', + $violations['application_deadline_winter_semester']->errorMessage(), + ); + } + /** + * @dataProvider validDeadlineDataProvider + */ + public function testValidApplicationDeadlines(string $deadline): void + { + $fixtureData = $this->fixtureData(); + $fixtureData['application_deadline_winter_semester'] = $deadline; + + $violations = $this->sut->validatePublish($fixtureData); + $this->assertCount(0, $violations->getArrayCopy()); + } + + public function invalidDeadlineDataProvider(): array + { + return [ + ['1'], + ['ab.bc.'], + ['12.123'], + ['12.13.'], + ['31.04.'], + ['30.04'], + ['1.4.'], + ]; + } + + public function validDeadlineDataProvider(): array + { + return [ + ['12.12.'], + ['01.01.'], + ['30.04.'], + ['31.08.'], + ['20.02.'], + [''], + ]; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_html_input.html b/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_html_input.html new file mode 100644 index 000000000..33ba68090 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_html_input.html @@ -0,0 +1,24 @@ +

test test

+ +
+ +

Heading Level 3

+ +

Heading Level 2

+ +
    +
  • Unordered list
  • +
+ +
    +
  1. Ordered list
  2. +
+ +
+
term
+
details
+
+ +[fau-video attr="56"] + +[wrong_shortcode] diff --git a/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_html_output.html b/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_html_output.html new file mode 100644 index 000000000..5a34c1882 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_html_output.html @@ -0,0 +1,22 @@ +

test test

+ +
+ +

Heading Level 3

+ +Heading Level 2 + +
    +
  • Unordered list
  • +
+ +
    +
  1. Ordered list
  2. +
+ +
+
term
+
details
+
+ +[fau-video attr="56"] diff --git a/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_serialized_blocks_input.html b/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_serialized_blocks_input.html new file mode 100644 index 000000000..16e709082 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_serialized_blocks_input.html @@ -0,0 +1,45 @@ + +

test test

+ + + +
+ + + +

Heading Level 3

+ + + +

Heading Level 2

+ + + +
    +
  • Unordered list
  • +
+ + + +
    +
  1. Ordered list
  2. +
+ + + +
+
term
+ + + +
details
+
+ + + +[fau-video attr="56"] + + + +[wrong_shortcode] + diff --git a/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_serialized_blocks_output.html b/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_serialized_blocks_output.html new file mode 100644 index 000000000..24e58b4b3 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/resources/fixtures/content_field_serialized_blocks_output.html @@ -0,0 +1,37 @@ + +

test test

+ + + +
+ + + +

Heading Level 3

+ + + +
    +
  • Unordered list
  • +
+ + + +
    +
  1. Ordered list
  2. +
+ + + +
+
term
+ + + +
details
+
+ + + +[fau-video attr="56"] + diff --git a/vendor/rrze/fau-studium-common/tests/resources/fixtures/degree_program.json b/vendor/rrze/fau-studium-common/tests/resources/fixtures/degree_program.json new file mode 100644 index 000000000..0c8ce1a90 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/resources/fixtures/degree_program.json @@ -0,0 +1,668 @@ +{ + "id": 25, + "slug": { + "id": "post:25:post_name", + "de": "master-of-art-fau-od", + "en": "master-of-art-fau-en-ode" + }, + "featured_image": { + "id": 9, + "url": "https:\/\/fau.localhost\/wp-content\/uploads\/2022\/12\/viber_image_2022-05-27_15-30-39-852.jpg" + }, + "teaser_image": { + "id": 14, + "url": "https:\/\/fau.localhost\/wp-content\/uploads\/2022\/12\/abstract-1-1528080.jpg" + }, + "title": { + "id": "post:25:title", + "de": "Master of Art FAU", + "en": "Master of Art FAU EN" + }, + "subtitle": { + "id": "post_meta:25:subtitle", + "de": "Subtitle", + "en": "Subtitle EN" + }, + "standard_duration": "6", + "fee_required": true, + "start": [ + { + "id": "term:21:name", + "de": "Summer", + "en": "Summer EN" + }, + { + "id": "term:22:name", + "de": "Winter", + "en": "Winter EN" + } + ], + "number_of_students": { + "id": "term:9", + "name": ">50", + "description": "

Less<\/p>" + }, + "teaching_language": { + "id": "term:10:name", + "de": "German Formal", + "en": "German Formal EN" + }, + "attributes": [ + { + "id": "term:5:name", + "de": "DE", + "en": "EN" + }, + { + "id": "term:34:name", + "de": "New DE", + "en": "New EN" + } + ], + "degree": { + "id": "term:7", + "name": { + "id": "term:7:name", + "de": "One Degree", + "en": "One Degree EN" + }, + "abbreviation": { + "id": "term_meta:7:abbreviation", + "de": "OD", + "en": "ODE" + }, + "parent": { + "id": "term:26", + "name": { + "id": "term:26:name", + "de": "Bachelorstudiengänge", + "en": "Bachelor Degrees" + }, + "abbreviation": { + "id": "term_meta:26:abbreviation", + "de": "", + "en": "" + }, + "parent": null + } + }, + "faculty": [ + { + "id": "term:11", + "name": { + "id": "term:11:name", + "de": "Faculty Math", + "en": "Faculty Math EN" + }, + "link_text": { + "id": "term_meta:11:link_text", + "de": "Link Faculty Math", + "en": "Link Faculty Math EN" + }, + "link_url": { + "id": "term_meta:11:link_url", + "de": "https:\/\/fau.localhost\/faculty-math", + "en": "https:\/\/fau.localhost\/faculty-math-en" + } + } + ], + "location": [ + { + "id": "term:22:name", + "de": "Study location", + "en": "Study location EN" + } + ], + "subject_groups": [ + { + "id": "term:23:name", + "de": "Subject Bio", + "en": "Subject Bio EN" + } + ], + "videos": [ + "https:\/\/www.youtube.com\/", + "https:\/\/vimeo.com\/" + ], + "meta_description": { + "id": "post_meta:25:meta_description", + "de": "Meta description.", + "en": "Meta description EN." + }, + "content": { + "about": { + "title": { + "id": "option:fau_about", + "de": "Worum geht es im Studiengang?", + "en": "What is the degree program about?" + }, + "description": { + "id": "post_meta:25:about", + "de": "It's very interesting.", + "en": "It's very interesting EN." + } + }, + "structure": { + "title": { + "id": "option:fau_structure", + "de": "", + "en": "" + }, + "description": { + "id": "post_meta:25:structure", + "de": "Structure description.", + "en": "Structure description EN." + } + }, + "specializations": { + "title": { + "id": "option:fau_specializations", + "de": "Spec title", + "en": "Spec title EN" + }, + "description": { + "id": "post_meta:25:specializations", + "de": "Specializations description.", + "en": "Specializations description EN." + } + }, + "qualities_and_skills": { + "title": { + "id": "option:fau_qualities_and_skills", + "de": "Qualities ans skills title.", + "en": "Qualities ans skills title EN." + }, + "description": { + "id": "post_meta:25:qualities_and_skills", + "de": "Qualities ans skills.", + "en": "Qualities ans skills EN." + } + }, + "why_should_study": { + "title": { + "id": "option:fau_why_should_study", + "de": "Gute Gr\u00fcnde f\u00fcr ein Studium an der FAU1232", + "en": "Why should I study at FAU?" + }, + "description": { + "id": "post_meta:25:why_should_study", + "de": "Why should study description.", + "en": "Why should study description EN." + } + }, + "career_prospects": { + "title": { + "id": "option:fau_career_prospects", + "de": "Career title", + "en": "Career title EN." + }, + "description": { + "id": "post_meta:25:career_prospects", + "de": "Career description.", + "en": "Career description EN." + } + }, + "special_features": { + "title": { + "id": "option:fau_special_features", + "de": "Special title", + "en": "Special title EN" + }, + "description": { + "id": "post_meta:25:special_features", + "de": "Special description", + "en": "Special description EN" + } + }, + "testimonials": { + "title": { + "id": "option:fau_testimonials", + "de": "Erfahrungsberichte", + "en": "Testimonials" + }, + "description": { + "id": "post_meta:25:testimonials", + "de": "Testimonial description", + "en": "Testimonial description EN" + } + } + }, + "admission_requirements": { + "bachelor_or_teaching_degree": { + "id": "term:13", + "name": { + "id": "term:13:name", + "de": "Admission Bachelor", + "en": "Admission Bachelor EN" + }, + "link_text": { + "id": "term_meta:13:link_text", + "de": "Link Admission Bachelor", + "en": "Link Admission Bachelor" + }, + "link_url": { + "id": "term_meta:13:link_url", + "de": "https:\/\/fau.localhost\/admission-bachelor", + "en": "https:\/\/fau.localhost\/admission-bachelor-en" + }, + "parent": { + "id": "term:123", + "name": { + "id": "term:123:name", + "de": "Frei", + "en": "Free" + }, + "link_text": { + "id": "term_meta:123:link_text", + "de": "", + "en": "" + }, + "link_url": { + "id": "term_meta:123:link_url", + "de": "", + "en": "" + }, + "parent": null, + "slug": "frei" + }, + "slug": "admission_bachelor" + }, + "teaching_degree_higher_semester": { + "id": "term:24", + "name": { + "id": "term:24:name", + "de": "Admission requirement for entering a Bachelor's\/teaching degree at a higher semester", + "en": "Admission requirement for entering a Bachelor's\/teaching degree at a higher semester EN" + }, + "link_text": { + "id": "term_meta:24:link_text", + "de": "Link to Admission requirement for entering a Bachelor's\/teaching degree at a higher semester", + "en": "Link to Admission requirement for entering a Bachelor's\/teaching degree at a higher semester EN" + }, + "link_url": { + "id": "term_meta:24:link_url", + "de": "https:\/\/fau.localhost\/higher-semester", + "en": "https:\/\/fau.localhost\/higher-semester-en" + }, + "parent": { + "id": "term:124", + "name": { + "id": "term:124:name", + "de": "Frei", + "en": "Free" + }, + "link_text": { + "id": "term_meta:124:link_text", + "de": "", + "en": "" + }, + "link_url": { + "id": "term_meta:124:link_url", + "de": "", + "en": "" + }, + "parent": null, + "slug": "frei" + }, + "slug": "admission_higher_semester" + }, + "master": { + "id": "term:19", + "name": { + "id": "term:19:name", + "de": "Admission requirement Master\u2019s degree", + "en": "Admission requirement Master\u2019s degree EN" + }, + "link_text": { + "id": "term_meta:19:link_text", + "de": "Link to Admission requirement Master\u2019s degree", + "en": "Link to Admission requirement Master\u2019s degree EN" + }, + "link_url": { + "id": "term_meta:19:link_url", + "de": "https:\/\/fau.localhost\/admission-master", + "en": "https:\/\/fau.localhost\/admission-master-en" + }, + "parent": { + "id": "term:125", + "name": { + "id": "term:125:name", + "de": "Nich Frei", + "en": "Not Free" + }, + "link_text": { + "id": "term_meta:125:link_text", + "de": "", + "en": "" + }, + "link_url": { + "id": "term_meta:125:link_url", + "de": "", + "en": "" + }, + "parent": null, + "slug": "nich_frei" + }, + "slug": "admission_master" + } + }, + "content_related_master_requirements": { + "id": "post_meta:25:content_related_master_requirements", + "de": "Master requirements.", + "en": "Master requirements EN." + }, + "application_deadline_winter_semester": "01.12.", + "application_deadline_summer_semester": "01.07.", + "details_and_notes": { + "id": "post_meta:25:details_and_notes", + "de": "Notes.", + "en": "Notes EN." + }, + "language_skills": { + "id": "post_meta:25:language_skills", + "de": "C1", + "en": "C1" + }, + "language_skills_humanities_faculty": "Excellent", + "german_language_skills_for_international_students": { + "id": "term:16", + "name": { + "id": "term:16:name", + "de": "German language skills for international students", + "en": "German language skills for international students EN" + }, + "link_text": { + "id": "term_meta:16:link_text", + "de": "Link to german language skills for international students", + "en": "Link to german language skills for international students EN" + }, + "link_url": { + "id": "term_meta:16:link_url", + "de": "https:\/\/fau.localhost\/german-language-skills-international-students", + "en": "https:\/\/fau.localhost\/german-language-skills-international-students-en" + } + }, + "start_of_semester": { + "id": "option:fau_start_of_semester", + "name": { + "id": "option:fau_start_of_semester:name", + "de": "Early start", + "en": "Early start EN" + }, + "link_text": { + "id": "option:fau_start_of_semester:link_text", + "de": "Link to Start of Semester", + "en": "Link to Start of Semester EN" + }, + "link_url": { + "id": "option:fau_start_of_semester:link_url", + "de": "https:\/\/fau.localhost\/start-of-semester", + "en": "https:\/\/fau.localhost\/start-of-semester-en" + } + }, + "semester_dates": { + "id": "option:fau_semester_dates", + "name": { + "id": "option:fau_semester_dates:name", + "de": "1/09-23/12", + "en": "1/09-23/12" + }, + "link_text": { + "id": "option:fau_semester_dates:link_text", + "de": "Link text Semester dates", + "en": "Link text Semester dates EN" + }, + "link_url": { + "id": "option:fau_semester_dates:link_url", + "de": "https:\/\/fau.localhost\/semester-dates", + "en": "https:\/\/fau.localhost\/semester-dates-en" + } + }, + "examinations_office": { + "id": "term:15", + "name": { + "id": "term:15:name", + "de": "Examinations Office", + "en": "Examinations Office EN" + }, + "link_text": { + "id": "term_meta:15:link_text", + "de": "Link Examinations Office", + "en": "Link Examinations Office EN" + }, + "link_url": { + "id": "term_meta:15:link_url", + "de": "https:\/\/fau.localhost\/examinations-office", + "en": "https:\/\/fau.localhost\/examinations-office-en" + } + }, + "examination_regulations": "https://fau.localhost/examinations-regulations", + "module_handbook": "Module handbook value", + "url": { + "id": "post_meta:25:url", + "de": "https:\/\/fau.localhost\/degree", + "en": "https:\/\/fau.localhost\/degree-program" + }, + "department": { + "id": "post_meta:25:department", + "de": "https:\/\/fau.localhost\/science", + "en": "https:\/\/fau.localhost\/science-en" + }, + "student_advice": { + "id": "option:fau_student_advice", + "name": { + "id": "option:fau_student_advice:name", + "de": "Student Advice and Career Service", + "en": "Student Advice and Career Service EN" + }, + "link_text": { + "id": "option:fau_student_advice:link_text", + "de": "Link Student Advice and Career Service", + "en": "Link Student Advice and Career Service EN" + }, + "link_url": { + "id": "option:fau_student_advice:link_url", + "de": "https:\/\/fau.localhost\/career-service", + "en": "https:\/\/fau.localhost\/career-service-en" + } + }, + "subject_specific_advice": { + "id": "term:6", + "name": { + "id": "term:6:name", + "de": "Advice", + "en": "Advice EN" + }, + "link_text": { + "id": "term_meta:6:link_text", + "de": "Link to Advice", + "en": "Link to Advice EN" + }, + "link_url": { + "id": "term_meta:6:link_url", + "de": "https:\/\/fau.localhost\/advice", + "en": "https:\/\/fau.localhost\/advice-en" + } + }, + "service_centers": { + "id": "option:fau_service_centers", + "name": { + "id": "option:fau_service_centers:name", + "de": "Counseling and Service Centers at FAU", + "en": "Counseling and Service Centers at FAU EN" + }, + "link_text": { + "id": "option:fau_service_centers:link_text", + "de": "Link Counseling and Service Centers at FAU", + "en": "Link Counseling and Service Centers at FAU EN" + }, + "link_url": { + "id": "option:fau_service_centers:link_url", + "de": "https:\/\/fau.localhost\/counseling", + "en": "https:\/\/fau.localhost\/counseling-en" + } + }, + "info_brochure": "Info Brochure 2023", + "semester_fee": { + "id": "option:fau_semester_fee", + "name": { + "id": "option:fau_semester_fee:name", + "de": "Semester fee", + "en": "Semester fee EN" + }, + "link_text": { + "id": "option:fau_semester_fee:link_text", + "de": "Link Semester fee", + "en": "Link Semester fee EN" + }, + "link_url": { + "id": "option:fau_semester_fee:link_url", + "de": "https:\/\/fau.localhost\/semester-fee", + "en": "https:\/\/fau.localhost\/semester-fee-en" + } + }, + "degree_program_fees": { + "id": "post_meta:25:degree_program_fees", + "de": "1000 EUR", + "en": "EUR 1000" + }, + "abroad_opportunities": { + "id": "option:fau_abroad_opportunities", + "name": { + "id": "option:fau_abroad_opportunities:name", + "de": "Opportunities for spending time abroad", + "en": "Opportunities for spending time abroad EN" + }, + "link_text": { + "id": "option:fau_abroad_opportunities:link_text", + "de": "Link Opportunities for spending time abroad", + "en": "Link Opportunities for spending time abroad EN" + }, + "link_url": { + "id": "option:fau_abroad_opportunities:link_url", + "de": "https:\/\/fau.localhost\/abroad", + "en": "https:\/\/fau.localhost\/abroad-en" + } + }, + "keywords": [ + { + "id": "term:17:name", + "de": "Keyword 1", + "en": "Keyword 1 EN" + }, + { + "id": "term:18:name", + "de": "Keyword 2", + "en": "Keyword 2 EN" + } + ], + "area_of_study": [ + { + "id": "term:3", + "name": { + "id": "term:3:name", + "de": "Biology", + "en": "Biology EN" + }, + "link_text": { + "id": "term_meta:3:link_text", + "de": "Link Biology", + "en": "Link Biology" + }, + "link_url": { + "id": "term_meta:3:link_url", + "de": "https:\/\/fau.localhost\/biology", + "en": "https:\/\/fau.localhost\/biology-en" + } + }, + { + "id": "term:38", + "name": { + "id": "term:38:name", + "de": "Math", + "en": "Math EN" + }, + "link_text": { + "id": "term_meta:38:link_text", + "de": "Link Math", + "en": "Link Math EN" + }, + "link_url": { + "id": "term_meta:38:link_url", + "de": "https:\/\/fau.localhost\/biology-math", + "en": "https:\/\/fau.localhost\/biology-math-en" + } + } + ], + "combinations": [ + 26, + 28 + ], + "limited_combinations": [ + 26 + ], + "notes_for_international_applicants": { + "id": "option:fau_notes_for_international_applicants", + "name": { + "id": "option:fau_notes_for_international_applicants:name", + "de": "Notes for international applicants", + "en": "Notes for international applicants EN" + }, + "link_text": { + "id": "option:fau_notes_for_international_applicants:link_text", + "de": "Link to notes for international applicants", + "en": "Link to notes for international applicants EN" + }, + "link_url": { + "id": "option:fau_notes_for_international_applicants:link_url", + "de": "https:\/\/fau.localhost\/notes-for-intl-applicants", + "en": "https:\/\/fau.localhost\/notes-for-intl-applicants-en" + } + }, + "student_initiatives": { + "id": "option:student_initiatives", + "name": { + "id": "option:student_initiatives:name", + "de": "Students' Union\/Student Initiatives", + "en": "Students' Union/Student Initiatives EN" + }, + "link_text": { + "id": "option:student_initiatives:link_text", + "de": "Link Students' Union\/Student Initiatives", + "en": "Link Students' Union\/Student Initiatives EN" + }, + "link_url": { + "id": "option:student_initiatives:link_url", + "de": "https:\/\/fau.localhost\/fsi", + "en": "https:\/\/fau.localhost\/fsi-en" + } + }, + "apply_now_link": { + "id": "term:39", + "name": { + "id": "term:39:name", + "de": "Campo", + "en": "Campo" + }, + "link_text": { + "id": "term_meta:39:link_text", + "de": "Apply now", + "en": "Apply now" + }, + "link_url": { + "id": "term_meta:39:link_url", + "de": "https://campo.fau.de", + "en": "https://campo.fau.de" + } + }, + "entry_text": { + "id": "post_meta:25:entry_text", + "de": "Einstiegtext (werbend)", + "en": "Entry text (promotional)" + }, + "campo_keys": { + "degree": "185", + "area_of_study": "85", + "location": "E" + } +} diff --git a/vendor/rrze/fau-studium-common/tests/resources/templates/hello.php b/vendor/rrze/fau-studium-common/tests/resources/templates/hello.php new file mode 100644 index 000000000..35a44d972 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/resources/templates/hello.php @@ -0,0 +1,11 @@ + $hello] = $data; + +echo $hello; diff --git a/vendor/rrze/fau-studium-common/tests/resources/templates/list.php b/vendor/rrze/fau-studium-common/tests/resources/templates/list.php new file mode 100644 index 000000000..ab0427205 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/resources/templates/list.php @@ -0,0 +1,21 @@ + $list] = $data; ?> + +

    + listItems() as $item) { + echo $renderer->render('partials/item.php', ['item' => $item]); + } ?> +
diff --git a/vendor/rrze/fau-studium-common/tests/resources/templates/partials/item.php b/vendor/rrze/fau-studium-common/tests/resources/templates/partials/item.php new file mode 100644 index 000000000..c867066ae --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/resources/templates/partials/item.php @@ -0,0 +1,22 @@ + $item] = $data; ?> + +
  • render( + 'partials/link.php', + ['nested_array' => ['url' => $item->url(), 'title' => $item->title()]] +) ?> +
  • + + ['url' => $url, 'title' => $title]] = $data; ?> + + diff --git a/vendor/rrze/fau-studium-common/tests/src/AsserHtmlTrait.php b/vendor/rrze/fau-studium-common/tests/src/AsserHtmlTrait.php new file mode 100644 index 000000000..a283b0fed --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/AsserHtmlTrait.php @@ -0,0 +1,21 @@ +assertSame( + $this->normalizeSpaces($expected), + $this->normalizeSpaces($actual) + ); + } + + private function normalizeSpaces(string $html): string + { + return (string) preg_replace('/[\s]{2,}|\n/', '', $html); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/Dto/ListDto.php b/vendor/rrze/fau-studium-common/tests/src/Dto/ListDto.php new file mode 100644 index 000000000..885d5e18e --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/Dto/ListDto.php @@ -0,0 +1,31 @@ +title = $title; + $this->listItems = $listItems; + } + + public function title(): string + { + return $this->title; + } + + public function listItems(): array + { + return $this->listItems; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/Dto/ListItemDto.php b/vendor/rrze/fau-studium-common/tests/src/Dto/ListItemDto.php new file mode 100644 index 000000000..0e141342d --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/Dto/ListItemDto.php @@ -0,0 +1,28 @@ +url = $url; + $this->title = $title; + } + + public function url(): string + { + return $this->url; + } + + public function title(): string + { + return $this->title; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/FixtureDegreeProgramDataProviderTrait.php b/vendor/rrze/fau-studium-common/tests/src/FixtureDegreeProgramDataProviderTrait.php new file mode 100644 index 000000000..c5cb2d562 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/FixtureDegreeProgramDataProviderTrait.php @@ -0,0 +1,117 @@ + [$this->fixtureData()]; + } + + public function createEmptyDegreeProgram(int $id): DegreeProgram + { + return new DegreeProgram( + id: DegreeProgramId::fromInt($id), + slug: MultilingualString::empty(), + featuredImage: Image::empty(), + teaserImage: Image::empty(), + title: MultilingualString::empty(), + subtitle: MultilingualString::empty(), + standardDuration: '', + start: MultilingualList::new(), + numberOfStudents: NumberOfStudents::empty(), + teachingLanguage: MultilingualString::empty(), + attributes: MultilingualList::new(), + degree: Degree::empty(), + faculty: MultilingualLinks::new(), + location: MultilingualList::new(), + subjectGroups: MultilingualList::new(), + videos: ArrayOfStrings::new(), + metaDescription: MultilingualString::empty(), + keywords: MultilingualList::new(), + areaOfStudy: MultilingualLinks::new(), + entryText: MultilingualString::empty(), + content: Content::new( + about: ContentItem::new(MultilingualString::empty(), MultilingualString::empty()), + structure: ContentItem::new(MultilingualString::empty(), MultilingualString::empty()), + specializations: ContentItem::new(MultilingualString::empty(), MultilingualString::empty()), + qualitiesAndSkills: ContentItem::new(MultilingualString::empty(), MultilingualString::empty()), + whyShouldStudy: ContentItem::new(MultilingualString::empty(), MultilingualString::empty()), + careerProspects: ContentItem::new(MultilingualString::empty(), MultilingualString::empty()), + specialFeatures: ContentItem::new(MultilingualString::empty(), MultilingualString::empty()), + testimonials: ContentItem::new(MultilingualString::empty(), MultilingualString::empty()), + ), + admissionRequirements: AdmissionRequirements::new( + bachelorOrTeachingDegree: AdmissionRequirement::empty(), + teachingDegreeHigherSemester: AdmissionRequirement::empty(), + master: AdmissionRequirement::empty(), + ), + contentRelatedMasterRequirements: MultilingualString::empty(), + applicationDeadlineWinterSemester: '', + applicationDeadlineSummerSemester: '', + detailsAndNotes: MultilingualString::empty(), + languageSkills: MultilingualString::empty(), + languageSkillsHumanitiesFaculty: '', + germanLanguageSkillsForInternationalStudents: MultilingualLink::empty(), + startOfSemester: MultilingualLink::empty(), + semesterDates: MultilingualLink::empty(), + examinationsOffice: MultilingualLink::empty(), + examinationRegulations: '', + moduleHandbook: '', + url: MultilingualString::empty(), + department: MultilingualString::empty(), + studentAdvice: MultilingualLink::empty(), + subjectSpecificAdvice: MultilingualLink::empty(), + serviceCenters: MultilingualLink::empty(), + infoBrochure: '', + semesterFee: MultilingualLink::empty(), + feeRequired: false, + degreeProgramFees: MultilingualString::empty(), + abroadOpportunities: MultilingualLink::empty(), + notesForInternationalApplicants: MultilingualLink::empty(), + studentInitiatives: MultilingualLink::empty(), + applyNowLink: MultilingualLink::empty(), + combinations: DegreeProgramIds::new(), + limitedCombinations: DegreeProgramIds::new(), + campoKeys: CampoKeys::empty(), + ); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/RendererTestCase.php b/vendor/rrze/fau-studium-common/tests/src/RendererTestCase.php new file mode 100644 index 000000000..b92043bd1 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/RendererTestCase.php @@ -0,0 +1,25 @@ +sut = TemplateRenderer::new( + DirectoryLocator::new(TEMPLATES_DIR), + ); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/Repository/StubDegreeProgramRepository.php b/vendor/rrze/fau-studium-common/tests/src/Repository/StubDegreeProgramRepository.php new file mode 100644 index 000000000..cc8279658 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/Repository/StubDegreeProgramRepository.php @@ -0,0 +1,161 @@ + + */ + private array $store = []; + + public function getById(DegreeProgramId $degreeProgramId): DegreeProgram + { + return $this->store[$degreeProgramId->asInt()] + ?? throw new RuntimeException( + 'Could not find degree program with id ' . (string) $degreeProgramId->asInt() + ); + } + + public function save(DegreeProgram $degreeProgram): void + { + $raw = DegreeProgramViewRaw::fromDegreeProgram($degreeProgram); + $this->store[$raw->id()->asInt()] = $degreeProgram; + } + + public function findRaw(DegreeProgramId $degreeProgramId): ?DegreeProgramViewRaw + { + return isset($this->store[$degreeProgramId->asInt()]) + ? DegreeProgramViewRaw::fromDegreeProgram($this->store[$degreeProgramId->asInt()]) + : null; + } + + public function findTranslated(DegreeProgramId $degreeProgramId, string $languageCode): ?DegreeProgramViewTranslated + { + $raw = $this->findRaw($degreeProgramId); + if (!$raw instanceof DegreeProgramViewRaw) { + return null; + } + + $main = $this->translateDegreeProgram($raw, $languageCode); + foreach (MultilingualString::LANGUAGES as $code => $name) { + if ($code === $languageCode) { + continue; + } + + $main = $main->withTranslation( + $this->translateDegreeProgram($raw, $code), + $code + ); + } + + return $main; + } + + private function translateDegreeProgram( + DegreeProgramViewRaw $raw, + string $languageCode + ): DegreeProgramViewTranslated { + + return new DegreeProgramViewTranslated( + id: $raw->id(), + link: '', + slug: '', + lang: $languageCode, + featuredImage: ImageView::new( + $raw->featuredImage()->id(), + $raw->featuredImage()->url(), + '', + ), + teaserImage: ImageView::new( + $raw->teaserImage()->id(), + $raw->teaserImage()->url(), + '', + ), + title: $raw->title()->asString($languageCode), + subtitle: $raw->subtitle()->asString($languageCode), + standardDuration: $raw->standardDuration(), + feeRequired: $raw->isFeeRequired(), + start: $raw->start()->asArrayOfStrings($languageCode), + numberOfStudents: $raw->numberOfStudents()->asString(), + teachingLanguage: $raw->teachingLanguage()->asString($languageCode), + attributes: $raw->attributes()->asArrayOfStrings($languageCode), + degree: DegreeTranslated::fromDegree($raw->degree(), $languageCode), + faculty: Links::fromMultilingualLinks($raw->faculty(), $languageCode), + location: $raw->location()->asArrayOfStrings($languageCode), + subjectGroups: $raw->subjectGroups()->asArrayOfStrings($languageCode), + videos: $raw->videos(), + metaDescription: $raw->metaDescription()->asString($languageCode), + content: ContentTranslated::fromContent($raw->content(), $languageCode), + admissionRequirements: AdmissionRequirementsTranslated::fromAdmissionRequirements( + $raw->admissionRequirements(), + $languageCode + ), + contentRelatedMasterRequirements: $raw->contentRelatedMasterRequirements()->asString($languageCode), + applicationDeadlineWinterSemester: $raw->applicationDeadlineWinterSemester(), + applicationDeadlineSummerSemester: $raw->applicationDeadlineSummerSemester(), + detailsAndNotes: $raw->detailsAndNotes()->asString($languageCode), + languageSkills: $raw->languageSkills()->asString($languageCode), + languageSkillsHumanitiesFaculty: $raw->languageSkillsHumanitiesFaculty(), + germanLanguageSkillsForInternationalStudents: Link::fromMultilingualLink( + $raw->germanLanguageSkillsForInternationalStudents(), + $languageCode + ), + startOfSemester: Link::fromMultilingualLink($raw->startOfSemester(), $languageCode), + semesterDates: Link::fromMultilingualLink($raw->semesterDates(), $languageCode), + examinationsOffice: Link::fromMultilingualLink($raw->examinationsOffice(), $languageCode), + examinationRegulations: $raw->examinationRegulations(), + moduleHandbook: $raw->moduleHandbook(), + url: $raw->url()->asString($languageCode), + department: $raw->department()->asString($languageCode), + studentAdvice: Link::fromMultilingualLink($raw->studentAdvice(), $languageCode), + subjectSpecificAdvice: Link::fromMultilingualLink($raw->subjectSpecificAdvice(), $languageCode), + serviceCenters: Link::fromMultilingualLink($raw->serviceCenters(), $languageCode), + infoBrochure: $raw->infoBrochure(), + semesterFee: Link::fromMultilingualLink($raw->semesterFee(), $languageCode), + degreeProgramFees: $raw->degreeProgramFees()->asString($languageCode), + abroadOpportunities: Link::fromMultilingualLink($raw->abroadOpportunities(), $languageCode), + keywords: $raw->keywords()->asArrayOfStrings($languageCode), + areaOfStudy: Links::fromMultilingualLinks($raw->areaOfStudy(), $languageCode), + combinations: RelatedDegreePrograms::new(), + limitedCombinations: RelatedDegreePrograms::new(), + notesForInternationalApplicants: Link::fromMultilingualLink($raw->notesForInternationalApplicants(), $languageCode), + applyNowLink: Link::fromMultilingualLink($raw->applyNowLink(), $languageCode), + entryText: $raw->entryText()->asString($languageCode), + campoKeys: $raw->campoKeys()->asArray(), + ); + } + + public function findRawCollection(CollectionCriteria $criteria): PaginationAwareCollection + { + return new StubPaginationAwareCollection(); + } + + public function findTranslatedCollection(CollectionCriteria $criteria, string $languageCode): PaginationAwareCollection + { + return new StubPaginationAwareCollection(); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/Repository/StubPaginationAwareCollection.php b/vendor/rrze/fau-studium-common/tests/src/Repository/StubPaginationAwareCollection.php new file mode 100644 index 000000000..8b4b16f63 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/Repository/StubPaginationAwareCollection.php @@ -0,0 +1,50 @@ +currentPage; + } + + public function nextPage(): ?int + { + return $this->nextPage; + } + + public function previousPage(): ?int + { + return $this->previousPage; + } + + public function maxPages(): int + { + return $this->maxPages; + } + + public function totalItems(): int + { + return $this->totalItems; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/Sanitizer/StubSanitizer.php b/vendor/rrze/fau-studium-common/tests/src/Sanitizer/StubSanitizer.php new file mode 100644 index 000000000..cbd76a4b1 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/Sanitizer/StubSanitizer.php @@ -0,0 +1,20 @@ +prefix . $content; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/UnitTestCase.php b/vendor/rrze/fau-studium-common/tests/src/UnitTestCase.php new file mode 100644 index 000000000..0a7d3dafc --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/UnitTestCase.php @@ -0,0 +1,27 @@ +result; + } + + public function validateDraft(array $data): Violations + { + return Violations::new(); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/WpDbLess/WpDbLessTestCase.php b/vendor/rrze/fau-studium-common/tests/src/WpDbLess/WpDbLessTestCase.php new file mode 100644 index 000000000..81deae271 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/WpDbLess/WpDbLessTestCase.php @@ -0,0 +1,138 @@ +wpHook = new WpHook(); + $this->wpOption = new WpOption([ + 'siteurl' => 'https://wp-db-less', + ]); + + if (!defined('ABSPATH')) { + define('ABSPATH', (string) getcwd() . '/vendor/johnpbloch/wordpress-core/'); + } + + require_once ABSPATH . 'wp-includes/class-wpdb.php'; + $GLOBALS['wpdb'] = new WpDbStub(); + + $this->wpHook->addHook( + 'alloptions', + [$this->wpOption, 'options'] + ); + } + + protected function tearDown(): void + { + unset($GLOBALS['wpdb'], $GLOBALS['wp_filter']); + } + + public function run(TestResult $result = null): TestResult + { + $this->runTestInSeparateProcess = true; + + return parent::run($result); + } + + protected function runTest(): void + { + if ($this->throwable) { + parent::runTest(); + return; + } + + $hook = $this->detectHook() ?? 'muplugins_loaded'; + + // phpcs:disable Inpsyde.CodeQuality.StaticClosure.PossiblyStaticClosure + $this->runWithThrowableCatching($hook, function () { + $this->setUpAfterWordPressLoaded(); + parent::runTest(); + }); + + $this->loadWordPress(); + } + + private function loadWordPress(): void + { + // phpcs:disable Inpsyde.CodeQuality.VariablesName.SnakeCaseVar + $table_prefix = 'wp_db_less_'; + require_once ABSPATH . 'wp-settings.php'; + } + + /** + * Exception throwing inside WordPress hook + * is not cached by \PHPUnit\Framework\TestCase::runTest + * so we provide a workaround to catch it and rethrow + * with fake assertThrowable test method. + */ + private function runWithThrowableCatching( + string $hook, + callable $callback, + ): void { + + $exceptionAwareCallback = function () use ($callback): void { + try { + $callback(); + } catch (Throwable $throwable) { + $this->throwable = $throwable; + /** @psalm-suppress InternalMethod */ + $this->setName('assertThrowable'); + $this->runTest(); + } + }; + + $this->wpHook->addHook($hook, $exceptionAwareCallback, 0); + } + + /** + * @internal + */ + protected function assertThrowable(): void + { + if ($this->throwable instanceof Throwable) { + throw $this->throwable; + } + } + + /** + * @psalm-suppress InternalMethod + * @psalm-suppress InternalClass + */ + private function detectHook(): ?string + { + $annotations = TestUtil::parseTestMethodAnnotations( + static::class, + $this->getName() + ); + + if (!isset($annotations['method']['wp-hook'][0])) { + return null; + } + + return (string) $annotations['method']['wp-hook'][0]; + } + + /** + * phpcs:disable Inpsyde.CodeQuality.NoAccessors.NoSetter + */ + public function setUpAfterWordPressLoaded(): void + { + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/WpDbLess/WpDbStub.php b/vendor/rrze/fau-studium-common/tests/src/WpDbLess/WpDbStub.php new file mode 100644 index 000000000..c50b0b073 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/WpDbLess/WpDbStub.php @@ -0,0 +1,25 @@ + PHP_INT_MAX, + 'function' => $callback, + ]; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/src/WpDbLess/WpOption.php b/vendor/rrze/fau-studium-common/tests/src/WpDbLess/WpOption.php new file mode 100644 index 000000000..5f646e418 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/src/WpDbLess/WpOption.php @@ -0,0 +1,22 @@ +options[$optionName] = $optionValue; + } + + public function options(): array + { + return $this->options; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Application/Repository/CollectionCriteriaTest.php b/vendor/rrze/fau-studium-common/tests/unit/Application/Repository/CollectionCriteriaTest.php new file mode 100644 index 000000000..99392cafa --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Application/Repository/CollectionCriteriaTest.php @@ -0,0 +1,49 @@ +assertSame(1, $sut->page()); + $this->assertSame(10, $sut->perPage()); + + $sut = $sut->withoutPagination(); + $this->assertSame(1, $sut->page()); + $this->assertSame(-1, $sut->perPage()); + + $sut = $sut->withPage(2)->withPerPage(20); + $this->assertSame(2, $sut->page()); + $this->assertSame(20, $sut->perPage()); + + $sut = $sut->toNextPage(); + $this->assertSame(3, $sut->page()); + $this->assertSame(20, $sut->perPage()); + } + + public function testLanguageCode(): void + { + $sut = CollectionCriteria::new()->withLanguage('en'); + $this->assertSame('en', $sut->languageCode()); + } + + public function testOrdering(): void + { + $sut = CollectionCriteria::new(); + $this->assertSame([], $sut->args()['order_by']); + + $sut = $sut->withOrderBy(['title' => 'asc']); + $this->assertSame(['title' => 'asc'], $sut->args()['order_by']); + + $sut = $sut->withOrderBy(['unknown' => null, 'title' => 'desc']); + $this->assertSame(['title' => 'desc'], $sut->args()['order_by']); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Content/PostTypeTest.php b/vendor/rrze/fau-studium-common/tests/unit/Content/PostTypeTest.php new file mode 100644 index 000000000..116a3ebd9 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Content/PostTypeTest.php @@ -0,0 +1,62 @@ +args(); + unset($publicArgs['labels']); + $this->assertSame( + [ + 'label' => 'Degree Programs', + 'hierarchical' => false, + 'supports' => [ + 'editor', + 'author', + ], + 'public' => true, + 'show_in_rest' => true, + 'rest_base' => 'degree-program', + 'menu_icon' => 'dashicons-welcome-learn-more', + ], + $publicArgs + ); + + $hiddenArgs = DegreeProgramPostType::hidden()->args(); + unset($hiddenArgs['labels']); + $this->assertSame( + [ + 'label' => 'Degree Programs', + 'hierarchical' => false, + 'supports' => [ + 'editor', + 'author', + ], + 'public' => false, + 'publicly_queryable' => true, + 'show_in_rest' => false, + ], + $hiddenArgs + ); + } + + public function testMerging(): void + { + $args = DegreeProgramPostType::public() + ->merge([ + 'public' => false, + 'template' => [], + ]) + ->args(); + + $this->assertFalse($args['public']); + $this->assertSame([], $args['template']); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Content/TaxonomyTest.php b/vendor/rrze/fau-studium-common/tests/unit/Content/TaxonomyTest.php new file mode 100644 index 000000000..5563fb4d4 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Content/TaxonomyTest.php @@ -0,0 +1,86 @@ + 'Degrees', + 'singular_name' => 'Degree', + 'search_items' => 'Search Degrees', + 'popular_items' => 'Popular Degrees', + 'all_items' => 'All Degrees', + 'parent_item' => 'Parent Degree', + 'parent_item_colon' => 'Parent Degree:', + 'edit_item' => 'Edit Degree', + 'view_item' => 'View Degree', + 'update_item' => 'Update Degree', + 'add_new_item' => 'Add New Degree', + 'new_item_name' => 'New Degree Name', + 'separate_items_with_commas' => 'Separate Degrees with commas', + 'add_or_remove_items' => 'Add or remove Degrees', + 'choose_from_most_used' => 'Choose from the most used Degrees', + 'not_found' => 'No Degrees found.', + 'no_terms' => 'No Degrees', + 'filter_by_item' => 'Filter by Degree', + 'items_list_navigation' => 'Degrees list navigation', + 'items_list' => 'Degrees list', + 'back_to_items' => '← Go to Degrees', + 'item_link' => 'Degree Link', + 'item_link_description' => 'A link to a Degree.', + ]; + + $this->assertSame( + [ + 'label' => 'Degrees', + 'labels' => $expectedLabels, + 'hierarchical' => true, + 'rest_base' => 'degree', + 'public' => true, + 'show_in_rest' => true, + 'meta_box_cb' => false, + ], + DegreeTaxonomy::public()->args() + ); + + $this->assertSame( + [ + 'label' => 'Degrees', + 'labels' => $expectedLabels, + 'hierarchical' => true, + 'rest_base' => 'degree', + 'public' => false, + 'show_in_rest' => false, + ], + DegreeTaxonomy::hidden()->args() + ); + } + + public function testShowAdminColumn(): void + { + $args = DegreeTaxonomy::public() + ->showAdminColumn() + ->args(); + $this->assertTrue($args['show_admin_column']); + } + + public function testMerging(): void + { + $args = DegreeTaxonomy::public() + ->merge([ + 'public' => false, + 'show_in_quick_edit' => true, + ]) + ->args(); + + $this->assertFalse($args['public']); + $this->assertTrue($args['show_in_quick_edit']); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/AdmissionRequirementsTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/AdmissionRequirementsTest.php new file mode 100644 index 000000000..38e425e2b --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/AdmissionRequirementsTest.php @@ -0,0 +1,111 @@ + [ + 'id' => 'term:5', + 'name' => [ + 'id' => 'term:5', + 'de' => 'Name Bachelor DE', + 'en' => 'Name Bachelor EN', + ], + 'link_text' => [ + 'id' => 'term:5', + 'de' => 'Link Text Bachelor DE', + 'en' => 'Link Text Bachelor EN', + ], + 'link_url' => [ + 'id' => 'term:5', + 'de' => 'Link URL Bachelor DE', + 'en' => 'Link URL Bachelor EN', + ], + 'parent' => null, + 'slug' => 'name_bachelor', + ], + 'teaching_degree_higher_semester' => [ + 'id' => 'term:6', + 'name' => [ + 'id' => 'term:6', + 'de' => 'Name Higher Semester DE', + 'en' => 'Name Higher Semester EN', + ], + 'link_text' => [ + 'id' => 'term:6', + 'de' => 'Link Text Higher Semester DE', + 'en' => 'Link Text Higher Semester EN', + ], + 'link_url' => [ + 'id' => 'term:6', + 'de' => 'Link URL Higher Semester DE', + 'en' => 'Link URL Higher Semester EN', + ], + 'parent' => [ + 'id' => 'term:123', + 'name' => [ + 'id' => 'term:123', + 'de' => 'Frei', + 'en' => 'Free', + ], + 'link_text' => [ + 'id' => 'term:123', + 'de' => '', + 'en' => '', + ], + 'link_url' => [ + 'id' => 'term:123', + 'de' => '', + 'en' => '', + ], + 'parent' => null, + 'slug' => 'frei', + ], + 'slug' => 'name_higher_semester', + ], + 'master' => [ + 'id' => 'term:7', + 'name' => [ + 'id' => 'term:7', + 'de' => 'Name Master DE', + 'en' => 'Name Master EN', + ], + 'link_text' => [ + 'id' => 'term:7', + 'de' => 'Link Text Master DE', + 'en' => 'Link Text Master EN', + ], + 'link_url' => [ + 'id' => 'term:7', + 'de' => 'Link URL Master DE', + 'en' => 'Link URL Master EN', + ], + 'parent' => null, + 'slug' => 'name_master', + ], + ]; + + $sut = AdmissionRequirements::fromArray($data); + $this->assertSame($data, $sut->asArray()); + $this->assertSame( + 'Name Bachelor EN', + $sut->bachelorOrTeachingDegree()->name()->asString('en') + ); + $this->assertSame( + 'Name Higher Semester DE', + $sut->teachingDegreeHigherSemester()->name()->asString('de') + ); + $this->assertSame( + 'Name Master DE', + $sut->master()->name()->asString('de') + ); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/ContentItemTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/ContentItemTest.php new file mode 100644 index 000000000..dc7b8715c --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/ContentItemTest.php @@ -0,0 +1,83 @@ + [ + 'id' => 'option:about', + 'de' => 'About Title DE', + 'en' => 'About Title EN', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'About Description DE', + 'en' => 'About Description EN', + ], + ]; + + $sut = ContentItem::fromArray($data); + $this->assertSame( + $data, + $sut->asArray(), + ); + + $this->assertSame( + 'About Title DE', + $sut->title()->inGerman(), + ); + $this->assertSame( + 'About Description EN', + $sut->description()->inEnglish(), + ); + } + + public function testDefault(): void + { + $data = [ + 'title' => [ + 'id' => 'option:original', + 'de' => 'About DE Original', + 'en' => '', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'About Description DE', + 'en' => 'About Description EN', + ], + ]; + + $sut = ContentItem::fromArray($data); + $sut = $sut->withDefaultTitle( + MultilingualString::fromTranslations( + 'default', + 'About DE Default', + 'About EN Default' + ) + ); + $this->assertSame( + [ + 'title' => [ + 'id' => 'option:original', + 'de' => 'About DE Original', + 'en' => 'About EN Default', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'About Description DE', + 'en' => 'About Description EN', + ], + ], + $sut->asArray() + ); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/ContentTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/ContentTest.php new file mode 100644 index 000000000..bba58c7f3 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/ContentTest.php @@ -0,0 +1,203 @@ +assertSame($contentData, $sut->asArray()); + $this->assertSame( + 'About Title DE', + $sut->about()->title()->asString('de') + ); + $this->assertSame( + 'Structure Description EN', + $sut->structure()->description()->asString('en') + ); + $this->assertSame( + 'Specializations Title EN', + $sut->specializations()->title()->asString('en') + ); + $this->assertSame( + 'Qualities Description DE', + $sut->qualitiesAndSkills()->description()->asString('de') + ); + $this->assertSame( + 'option:why_should_study', + $sut->whyShouldStudy()->title()->id() + ); + $this->assertSame( + 'Career Title DE', + $sut->careerProspects()->title()->inGerman() + ); + $this->assertSame( + 'Special Title EN', + $sut->specialFeatures()->title()->inEnglish() + ); + $this->assertSame( + 'Testimonials Description DE', + $sut->testimonials()->description()->inGerman() + ); + } + + /** + * @dataProvider contentDataProvider + */ + public function testMapDescriptions(array $contentData): void + { + $sut = Content::fromArray( + Content::mapDescriptions( + $contentData, + static fn(string $description) => '[Was processed]' . $description + ) + ); + + $this->assertSame( + 'About Title DE', + $sut->about()->title()->asString('de') + ); + $this->assertSame( + '[Was processed]Structure Description EN', + $sut->structure()->description()->asString('en') + ); + $this->assertSame( + 'Specializations Title EN', + $sut->specializations()->title()->asString('en') + ); + $this->assertSame( + '[Was processed]Qualities Description DE', + $sut->qualitiesAndSkills()->description()->asString('de') + ); + $this->assertSame( + 'option:why_should_study', + $sut->whyShouldStudy()->title()->id() + ); + $this->assertSame( + 'Career Title DE', + $sut->careerProspects()->title()->inGerman() + ); + $this->assertSame( + 'Special Title EN', + $sut->specialFeatures()->title()->inEnglish() + ); + $this->assertSame( + '[Was processed]Testimonials Description DE', + $sut->testimonials()->description()->inGerman() + ); + } + + public function contentDataProvider(): iterable + { + $data = [ + 'about' => [ + 'title' => [ + 'id' => 'option:about', + 'de' => 'About Title DE', + 'en' => 'About Title EN', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'About Description DE', + 'en' => 'About Description EN', + ], + ], + 'structure' => [ + 'title' => [ + 'id' => 'option:structure', + 'de' => 'Structure Title DE', + 'en' => 'Structure Title EN', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'Structure Description DE', + 'en' => 'Structure Description EN', + ], + ], + 'specializations' => [ + 'title' => [ + 'id' => 'option:specializations', + 'de' => 'Specializations Title DE', + 'en' => 'Specializations Title EN', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'Specializations Description DE', + 'en' => 'Specializations Description EN', + ], + ], + 'qualities_and_skills' => [ + 'title' => [ + 'id' => 'option:qualities_and_skills', + 'de' => 'Qualities Title DE', + 'en' => 'Qualities Title EN', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'Qualities Description DE', + 'en' => 'Qualities Description EN', + ], + ], + 'why_should_study' => [ + 'title' => [ + 'id' => 'option:why_should_study', + 'de' => 'Why Title DE', + 'en' => 'Why Title EN', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'Why Description DE', + 'en' => 'Why Description EN', + ], + ], + 'career_prospects' => [ + 'title' => [ + 'id' => 'option:career_prospects', + 'de' => 'Career Title DE', + 'en' => 'Career Title EN', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'Career Description DE', + 'en' => 'Career Description EN', + ], + ], + 'special_features' => [ + 'title' => [ + 'id' => 'option:special_features', + 'de' => 'Special Title DE', + 'en' => 'Special Title EN', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'Special Description DE', + 'en' => 'Special Description EN', + ], + ], + 'testimonials' => [ + 'title' => [ + 'id' => 'option:testimonials', + 'de' => 'Testimonials Title DE', + 'en' => 'Testimonials Title EN', + ], + 'description' => [ + 'id' => 'post_meta:23', + 'de' => 'Testimonials Description DE', + 'en' => 'Testimonials Description EN', + ], + ], + ]; + + yield 'basic_data' => [$data]; + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeProgramIdTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeProgramIdTest.php new file mode 100644 index 000000000..a1d52d019 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeProgramIdTest.php @@ -0,0 +1,18 @@ +assertSame($id, $sut->asInt()); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeProgramIdsTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeProgramIdsTest.php new file mode 100644 index 000000000..80f5254db --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeProgramIdsTest.php @@ -0,0 +1,18 @@ +assertSame($array, $sut->asArray()); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeProgramTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeProgramTest.php new file mode 100644 index 000000000..305df0de3 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeProgramTest.php @@ -0,0 +1,256 @@ +expectException(RuntimeException::class); + $this->expectExceptionMessage('Invalid entity id.'); + $sut = $this->createEmptyDegreeProgram(25); + $data = $this->fixtureData(); + $wrongId = 12312; + $data['id'] = $wrongId; + + $sut->publish( + $data, + new StubDataValidator(Violations::new()), + new StubSanitizer(), + ); + } + + public function testUpdateValidationFailed(): void + { + $violations = Violations::new(Violation::new('title', 'Empty title', 'empty_title')); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid publish degree program data.'); + $sut = $this->createEmptyDegreeProgram(25); + $data = $this->fixtureData(); + + $sut->publish( + $data, + new StubDataValidator($violations), + new StubSanitizer(), + ); + } + + public function testUpdateSuccessfully(): void + { + $sut = $this->createEmptyDegreeProgram(25); + $data = $this->fixtureData(); + $sut->publish( + $data, + new StubDataValidator(Violations::new()), + new StubSanitizer('[Was sanitized]'), + ); + $result = $sut->asArray(); + + $this->assertSame( + 25, + $result['id']->asInt() + ); + $this->assertSame( + 9, + $result['featured_image']->id() + ); + $this->assertSame( + 14, + $result['teaser_image']->id() + ); + $this->assertSame( + 'Master of Art FAU EN', + $result['title']->inEnglish() + ); + $this->assertSame( + 'Subtitle', + $result['subtitle']->inGerman() + ); + $this->assertSame( + 'Winter EN', + $result['start']->asArrayOfStrings('en')[1] + ); + $this->assertSame( + '

    Less

    ', + $result['number_of_students']->description() + ); + $this->assertSame( + 'German Formal', + $result['teaching_language']->inGerman() + ); + $this->assertSame( + 'DE', + $result['attributes']->asArrayOfStrings('de')[0] + ); + $this->assertSame( + 'One Degree', + $result['degree']->name()->inGerman() + ); + $this->assertSame( + 'Link Faculty Math EN', + $result['faculty']->asArray()[0]['link_text']['en'] + ); + $this->assertSame( + 'Study location', + $result['location']->asArrayOfStrings('de')[0] + ); + $this->assertSame( + 'Subject Bio EN', + $result['subject_groups']->asArrayOfStrings('en')[0] + ); + $this->assertSame( + [ + "https://www.youtube.com/", + "https://vimeo.com/", + ], + $result['videos']->getArrayCopy() + ); + $this->assertSame( + 'Meta description.', + $result['meta_description']->inGerman() + ); + // The title is missing in the fixture but added in the entity constructor as the default value. + $this->assertSame( + 'Aufbau und Struktur', + $result['content']->structure()->title()->inGerman() + ); + $this->assertSame( + '[Was sanitized]Structure description.', + $result['content']->structure()->description()->inGerman() + ); + $this->assertSame( + 'Admission Bachelor', + $result['admission_requirements']->bachelorOrTeachingDegree()->name()->inGerman() + ); + $this->assertSame( + '[Was sanitized]Master requirements.', + $result['content_related_master_requirements']->inGerman() + ); + $this->assertSame( + '01.12.', + $result['application_deadline_winter_semester'] + ); + $this->assertSame( + '01.07.', + $result['application_deadline_summer_semester'] + ); + $this->assertSame( + '[Was sanitized]Notes EN.', + $result['details_and_notes']->inEnglish() + ); + $this->assertSame( + '[Was sanitized]C1', + $result['language_skills']->inEnglish() + ); + $this->assertSame( + '[Was sanitized]Excellent', + $result['language_skills_humanities_faculty'] + ); + $this->assertSame( + 'https://fau.localhost/german-language-skills-international-students-en', + $result['german_language_skills_for_international_students']->linkUrl()->inEnglish() + ); + $this->assertSame( + 'Link to Start of Semester EN', + $result['start_of_semester']->linkText()->inEnglish() + ); + $this->assertSame( + 'Link text Semester dates EN', + $result['semester_dates']->linkText()->inEnglish() + ); + $this->assertSame( + 'Link Examinations Office EN', + $result['examinations_office']->linkText()->inEnglish() + ); + $this->assertSame( + 'https://fau.localhost/examinations-regulations', + $result['examination_regulations'] + ); + $this->assertSame( + 'Module handbook value', + $result['module_handbook'] + ); + $this->assertSame( + 'https://fau.localhost/science-en', + $result['department']->inEnglish(), + ); + $this->assertSame( + 'Link Student Advice and Career Service EN', + $result['student_advice']->linkText()->inEnglish() + ); + $this->assertSame( + 'Link to Advice EN', + $result['subject_specific_advice']->linkText()->inEnglish() + ); + $this->assertSame( + 'Link Counseling and Service Centers at FAU EN', + $result['service_centers']->linkText()->inEnglish() + ); + $this->assertSame( + 'Info Brochure 2023', + $result['info_brochure'] + ); + $this->assertSame( + 'https://fau.localhost/semester-fee', + $result['semester_fee']->linkUrl()->inGerman() + ); + $this->assertSame('EUR 1000', $result['degree_program_fees']->inEnglish()); + $this->assertSame( + 'Opportunities for spending time abroad', + $result['abroad_opportunities']->name()->inGerman() + ); + $this->assertSame( + 'Keyword 1 EN', + $result['keywords']->asArrayOfStrings('en')[0] + ); + $this->assertSame( + 'https://fau.localhost/biology', + $result['area_of_study']->asArray()[0]['link_url']['de'] + ); + $this->assertSame( + [26, 28], + $result['combinations']->asArray() + ); + $this->assertSame( + [26], + $result['limited_combinations']->asArray() + ); + $this->assertSame( + [26, 28], + $result['combinations_changeset']->added() + ); + $this->assertSame( + [], + $result['combinations_changeset']->removed() + ); + $this->assertSame( + [26], + $result['limited_combinations_changeset']->added() + ); + $this->assertSame( + [], + $result['limited_combinations_changeset']->removed() + ); + $this->assertSame( + 'Notes for international applicants EN', + $result['notes_for_international_applicants']->name()->inEnglish() + ); + $this->assertSame( + 'Students\' Union/Student Initiatives', + $result['student_initiatives']->name()->inGerman() + ); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeTest.php new file mode 100644 index 000000000..b787ece47 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/DegreeTest.php @@ -0,0 +1,78 @@ +assertSame( + '{"id":"","name":{"id":"","de":"","en":""},"abbreviation":{"id":"","de":"","en":""},"parent":null}', + json_encode($sut) + ); + } + + public function testFromArray(): void + { + $data = [ + 'id' => 'term:6', + 'name' => [ + 'id' => 'term:5', + 'de' => 'Lehramt Mittelschule', + 'en' => 'Teaching secondary education', + ], + 'abbreviation' => [ + 'id' => 'term:5', + 'de' => 'LM', + 'en' => 'TSE', + ], + 'parent' => [ + 'id' => 'term:26', + 'name' => [ + 'id' => 'term:26', + 'de' => 'Bachelorstudiengänge', + 'en' => 'Bachelor Degrees', + ], + 'abbreviation' => [ + 'id' => 'term:26', + 'de' => 'LM', + 'en' => 'TSE', + ], + 'parent' => null, + ], + ]; + + $sut = Degree::fromArray($data); + $this->assertSame($data, $sut->asArray()); + $this->assertSame( + 'Lehramt Mittelschule', + $sut->name()->inGerman() + ); + $this->assertSame( + 'Teaching secondary education', + $sut->name()->inEnglish() + ); + $this->assertSame( + 'LM', + $sut->abbreviation()->inGerman() + ); + $this->assertSame( + 'TSE', + $sut->abbreviation()->inEnglish() + ); + $this->assertSame( + 'Bachelorstudiengänge', + $sut->parent()->name()->inGerman() + ); + $this->assertSame( + 'Bachelor Degrees', + $sut->parent()->name()->inEnglish() + ); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/ImageTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/ImageTest.php new file mode 100644 index 000000000..2ea96b61f --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/ImageTest.php @@ -0,0 +1,29 @@ +assertEmpty($sut->id()); + $this->assertEmpty($sut->url()); + } + + public function testFromArray(): void + { + $array = [ + 'id' => 5, + 'url' => 'https://fau.localhost/wp-content/uploads/2022/12/abstract-1-1528080.jpg', + ]; + + $sut = Image::fromArray($array); + $this->assertSame($array, $sut->asArray()); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualLinkTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualLinkTest.php new file mode 100644 index 000000000..3ed4d406f --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualLinkTest.php @@ -0,0 +1,36 @@ + 'term:11', + 'name' => [ + 'id' => 'term:11', + 'de' => 'Faculty Math', + 'en' => 'Faculty Math EN', + ], + 'link_text' => [ + 'id' => 'term:11', + 'de' => 'Link Faculty Math', + 'en' => 'Link Faculty Math EN', + ], + 'link_url' => [ + 'id' => 'term:11', + 'de' => 'https://fau.localhost/faculty-math', + 'en' => 'https://fau.localhost/faculty-math-en', + ], + ]; + + $sut = MultilingualLink::fromArray($array); + $this->assertSame($array, $sut->asArray()); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualLinksTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualLinksTest.php new file mode 100644 index 000000000..ee25f7720 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualLinksTest.php @@ -0,0 +1,56 @@ + 'term:3', + 'name' => [ + 'id' => 'term:3', + 'de' => 'Biology', + 'en' => 'Biology EN', + ], + 'link_text' => [ + 'id' => 'term:3', + 'de' => 'Link Biology', + 'en' => 'Link Biology', + ], + 'link_url' => [ + 'id' => 'term:3', + 'de' => 'https://fau.localhost/biology', + 'en' => 'https://fau.localhost/biology-en', + ], + ], + [ + 'id' => 'term:38', + 'name' => [ + 'id' => 'term:38', + 'de' => 'Math', + 'en' => 'Math EN', + ], + 'link_text' => [ + 'id' => 'term:38', + 'de' => 'Link Math', + 'en' => 'Link Math EN', + ], + 'link_url' => [ + 'id' => 'term:38', + 'de' => 'https://fau.localhost/biology-math', + 'en' => 'https://fau.localhost/biology-math-en', + ], + ], + ]; + + $sut = MultilingualLinks::fromArray($array); + $this->assertSame($array, $sut->asArray()); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualListTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualListTest.php new file mode 100644 index 000000000..cb58da637 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualListTest.php @@ -0,0 +1,30 @@ + 'term:17', + 'de' => 'Keyword 1', + 'en' => 'Keyword 1 EN', + ], + [ + 'id' => 'term:18', + 'de' => 'Keyword 2', + 'en' => 'Keyword 2 EN', + ], + ]; + + $sut = MultilingualList::fromArray($array); + $this->assertSame($array, $sut->asArray()); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualStringTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualStringTest.php new file mode 100644 index 000000000..fa04487cb --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/MultilingualStringTest.php @@ -0,0 +1,82 @@ +assertEmpty($sut->id()); + $this->assertEmpty($sut->inGerman()); + $this->assertEmpty($sut->inEnglish()); + } + + public function testFromArray(): void + { + $array = [ + 'id' => 'term:17', + 'de' => 'Keyword 1', + 'en' => 'Keyword 1 EN', + ]; + $sut = MultilingualString::fromArray($array); + $this->assertSame($array, $sut->asArray()); + } + + public function testFromTranslations(): void + { + $array = [ + 'id' => 'term:17', + 'de' => 'Keyword 1', + 'en' => 'Keyword 1 EN', + ]; + $sut = MultilingualString::fromTranslations(...$array); + $this->assertSame($array, $sut->asArray()); + $this->assertSame('term:17', $sut->id()); + $this->assertSame('Keyword 1', $sut->inGerman()); + $this->assertSame('Keyword 1', $sut->asString('de')); + $this->assertSame('Keyword 1 EN', $sut->inEnglish()); + $this->assertSame('Keyword 1 EN', $sut->asString('en')); + } + + public function testDefault(): void + { + $sut = MultilingualString::fromTranslations( + 'term:17', + '', + 'Keyword 1 EN' + )->mergeWithDefault( + MultilingualString::fromTranslations( + 'default', + 'Default Keyword', + 'Default Keyword EN' + ) + ); + $this->assertSame('term:17', $sut->id()); + $this->assertSame('Default Keyword', $sut->inGerman()); + $this->assertSame('Keyword 1 EN', $sut->inEnglish()); + } + + public function testMapTranslations(): void + { + $array = [ + 'id' => 'term:17', + 'de' => 'Keyword 1', + 'en' => 'Keyword 1 EN', + ]; + $data = MultilingualString::mapTranslations( + $array, + (static fn(string $translation) => '[Was processed]' . $translation) + ); + $sut = MultilingualString::fromArray($data); + + $this->assertSame('term:17', $sut->id()); + $this->assertSame('[Was processed]Keyword 1', $sut->inGerman()); + $this->assertSame('[Was processed]Keyword 1 EN', $sut->inEnglish()); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/NumberOfStudentsTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/NumberOfStudentsTest.php new file mode 100644 index 000000000..8b660eb63 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/NumberOfStudentsTest.php @@ -0,0 +1,26 @@ + 'term:16', + 'name' => '>200', + 'description' => 'Many', + ]; + + $sut = NumberOfStudents::fromArray($array); + $this->assertSame($array, $sut->asArray()); + $this->assertSame('Many', $sut->description()); + $this->assertSame('>200', $sut->asString()); + $this->assertSame('term:16', $sut->id()); + } +} diff --git a/vendor/rrze/fau-studium-common/tests/unit/Domain/ViolationsTest.php b/vendor/rrze/fau-studium-common/tests/unit/Domain/ViolationsTest.php new file mode 100644 index 000000000..66aad03c5 --- /dev/null +++ b/vendor/rrze/fau-studium-common/tests/unit/Domain/ViolationsTest.php @@ -0,0 +1,36 @@ +add( + Violation::new('path1', 'message1', 'code1'), + Violation::new('path2', 'message2', 'code2'), + ); + + $this->assertSame($violations['path1']->path(), 'path1'); + $this->assertCount(2, $violations); + $this->assertSame([ + 'path1' => [ + 'path' => 'path1', + 'errorMessage' => 'message1', + 'errorCode' => 'code1', + ], + 'path2' => [ + 'path' => 'path2', + 'errorMessage' => 'message2', + 'errorCode' => 'code2', + ], + ], $violations->asArray()); + } +} diff --git a/vendor/webmozart/assert/CHANGELOG.md b/vendor/webmozart/assert/CHANGELOG.md new file mode 100644 index 000000000..56c8011de --- /dev/null +++ b/vendor/webmozart/assert/CHANGELOG.md @@ -0,0 +1,207 @@ +Changelog +========= + +## UNRELEASED + +## 1.11.0 + +### Added + +* Added explicit (non magic) `allNullOr*` methods, with `@psalm-assert` annotations, for better Psalm support. + +### Changed + +* Trait methods will now check the assertion themselves, instead of using `__callStatic` +* `isList` will now deal correctly with (modified) lists that contain `NaN` +* `reportInvalidArgument` now has a return type of `never`. + +### Removed + +* Removed `symfony/polyfill-ctype` as a dependency, and require `ext-cytpe` instead. + * You can still require the `symfony/polyfill-ctype` in your project if you need it, as it provides `ext-ctype` + +## 1.10.0 + +### Added + +* On invalid assertion, we throw a `Webmozart\Assert\InvalidArgumentException` +* Added `Assert::positiveInteger()` + +### Changed + +* Using a trait with real implementations of `all*()` and `nullOr*()` methods to improve psalm compatibility. + +### Removed + +* Support for PHP <7.2 + +## 1.9.1 + +## Fixed + +* provisional support for PHP 8.0 + +## 1.9.0 + +* added better Psalm support for `all*` & `nullOr*` methods +* These methods are now understood by Psalm through a mixin. You may need a newer version of Psalm in order to use this +* added `@psalm-pure` annotation to `Assert::notFalse()` +* added more `@psalm-assert` annotations where appropriate + +## Changed + +* the `all*` & `nullOr*` methods are now declared on an interface, instead of `@method` annotations. +This interface is linked to the `Assert` class with a `@mixin` annotation. Most IDE's have supported this +for a long time, and you should not lose any autocompletion capabilities. PHPStan has supported this since +version `0.12.20`. This package is marked incompatible (with a composer conflict) with phpstan version prior to that. +If you do not use PHPStan than this does not matter. + +## 1.8.0 + +### Added + +* added `Assert::notStartsWith()` +* added `Assert::notEndsWith()` +* added `Assert::inArray()` +* added `@psalm-pure` annotations to pure assertions + +### Fixed + +* Exception messages of comparisons between `DateTime(Immutable)` objects now display their date & time. +* Custom Exception messages for `Assert::count()` now use the values to render the exception message. + +## 1.7.0 (2020-02-14) + +### Added + +* added `Assert::notFalse()` +* added `Assert::isAOf()` +* added `Assert::isAnyOf()` +* added `Assert::isNotA()` + +## 1.6.0 (2019-11-24) + +### Added + +* added `Assert::validArrayKey()` +* added `Assert::isNonEmptyList()` +* added `Assert::isNonEmptyMap()` +* added `@throws InvalidArgumentException` annotations to all methods that throw. +* added `@psalm-assert` for the list type to the `isList` assertion. + +### Fixed + +* `ResourceBundle` & `SimpleXMLElement` now pass the `isCountable` assertions. +They are countable, without implementing the `Countable` interface. +* The doc block of `range` now has the proper variables. +* An empty array will now pass `isList` and `isMap`. As it is a valid form of both. +If a non-empty variant is needed, use `isNonEmptyList` or `isNonEmptyMap`. + +### Changed + +* Removed some `@psalm-assert` annotations, that were 'side effect' assertions See: + * [#144](https://github.com/webmozart/assert/pull/144) + * [#145](https://github.com/webmozart/assert/issues/145) + * [#146](https://github.com/webmozart/assert/pull/146) + * [#150](https://github.com/webmozart/assert/pull/150) +* If you use Psalm, the minimum version needed is `3.6.0`. Which is enforced through a composer conflict. +If you don't use Psalm, then this has no impact. + +## 1.5.0 (2019-08-24) + +### Added + +* added `Assert::uniqueValues()` +* added `Assert::unicodeLetters()` +* added: `Assert::email()` +* added support for [Psalm](https://github.com/vimeo/psalm), by adding `@psalm-assert` annotations where appropriate. + +### Fixed + +* `Assert::endsWith()` would not give the correct result when dealing with a multibyte suffix. +* `Assert::length(), minLength, maxLength, lengthBetween` would not give the correct result when dealing with multibyte characters. + +**NOTE**: These 2 changes may break your assertions if you relied on the fact that multibyte characters didn't behave correctly. + +### Changed + +* The names of some variables have been updated to better reflect what they are. +* All function calls are now in their FQN form, slightly increasing performance. +* Tests are now properly ran against HHVM-3.30 and PHP nightly. + +### Deprecation + +* deprecated `Assert::isTraversable()` in favor of `Assert::isIterable()` + * This was already done in 1.3.0, but it was only done through a silenced `trigger_error`. It is now annotated as well. + +## 1.4.0 (2018-12-25) + +### Added + +* added `Assert::ip()` +* added `Assert::ipv4()` +* added `Assert::ipv6()` +* added `Assert::notRegex()` +* added `Assert::interfaceExists()` +* added `Assert::isList()` +* added `Assert::isMap()` +* added polyfill for ctype + +### Fixed + +* Special case when comparing objects implementing `__toString()` + +## 1.3.0 (2018-01-29) + +### Added + +* added `Assert::minCount()` +* added `Assert::maxCount()` +* added `Assert::countBetween()` +* added `Assert::isCountable()` +* added `Assert::notWhitespaceOnly()` +* added `Assert::natural()` +* added `Assert::notContains()` +* added `Assert::isArrayAccessible()` +* added `Assert::isInstanceOfAny()` +* added `Assert::isIterable()` + +### Fixed + +* `stringNotEmpty` will no longer report "0" is an empty string + +### Deprecation + +* deprecated `Assert::isTraversable()` in favor of `Assert::isIterable()` + +## 1.2.0 (2016-11-23) + + * added `Assert::throws()` + * added `Assert::count()` + * added extension point `Assert::reportInvalidArgument()` for custom subclasses + +## 1.1.0 (2016-08-09) + + * added `Assert::object()` + * added `Assert::propertyExists()` + * added `Assert::propertyNotExists()` + * added `Assert::methodExists()` + * added `Assert::methodNotExists()` + * added `Assert::uuid()` + +## 1.0.2 (2015-08-24) + + * integrated Style CI + * add tests for minimum package dependencies on Travis CI + +## 1.0.1 (2015-05-12) + + * added support for PHP 5.3.3 + +## 1.0.0 (2015-05-12) + + * first stable release + +## 1.0.0-beta (2015-03-19) + + * first beta release diff --git a/vendor/webmozart/assert/LICENSE b/vendor/webmozart/assert/LICENSE new file mode 100644 index 000000000..9e2e3075e --- /dev/null +++ b/vendor/webmozart/assert/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Bernhard Schussek + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/webmozart/assert/README.md b/vendor/webmozart/assert/README.md new file mode 100644 index 000000000..3b2397a1a --- /dev/null +++ b/vendor/webmozart/assert/README.md @@ -0,0 +1,287 @@ +Webmozart Assert +================ + +[![Latest Stable Version](https://poser.pugx.org/webmozart/assert/v/stable.svg)](https://packagist.org/packages/webmozart/assert) +[![Total Downloads](https://poser.pugx.org/webmozart/assert/downloads.svg)](https://packagist.org/packages/webmozart/assert) + +This library contains efficient assertions to test the input and output of +your methods. With these assertions, you can greatly reduce the amount of coding +needed to write a safe implementation. + +All assertions in the [`Assert`] class throw an `Webmozart\Assert\InvalidArgumentException` if +they fail. + +FAQ +--- + +**What's the difference to [beberlei/assert]?** + +This library is heavily inspired by Benjamin Eberlei's wonderful [assert package], +but fixes a usability issue with error messages that can't be fixed there without +breaking backwards compatibility. + +This package features usable error messages by default. However, you can also +easily write custom error messages: + +``` +Assert::string($path, 'The path is expected to be a string. Got: %s'); +``` + +In [beberlei/assert], the ordering of the `%s` placeholders is different for +every assertion. This package, on the contrary, provides consistent placeholder +ordering for all assertions: + +* `%s`: The tested value as string, e.g. `"/foo/bar"`. +* `%2$s`, `%3$s`, ...: Additional assertion-specific values, e.g. the + minimum/maximum length, allowed values, etc. + +Check the source code of the assertions to find out details about the additional +available placeholders. + +Installation +------------ + +Use [Composer] to install the package: + +```bash +composer require webmozart/assert +``` + +Example +------- + +```php +use Webmozart\Assert\Assert; + +class Employee +{ + public function __construct($id) + { + Assert::integer($id, 'The employee ID must be an integer. Got: %s'); + Assert::greaterThan($id, 0, 'The employee ID must be a positive integer. Got: %s'); + } +} +``` + +If you create an employee with an invalid ID, an exception is thrown: + +```php +new Employee('foobar'); +// => Webmozart\Assert\InvalidArgumentException: +// The employee ID must be an integer. Got: string + +new Employee(-10); +// => Webmozart\Assert\InvalidArgumentException: +// The employee ID must be a positive integer. Got: -10 +``` + +Assertions +---------- + +The [`Assert`] class provides the following assertions: + +### Type Assertions + +Method | Description +-------------------------------------------------------- | -------------------------------------------------- +`string($value, $message = '')` | Check that a value is a string +`stringNotEmpty($value, $message = '')` | Check that a value is a non-empty string +`integer($value, $message = '')` | Check that a value is an integer +`integerish($value, $message = '')` | Check that a value casts to an integer +`positiveInteger($value, $message = '')` | Check that a value is a positive (non-zero) integer +`float($value, $message = '')` | Check that a value is a float +`numeric($value, $message = '')` | Check that a value is numeric +`natural($value, $message= ''')` | Check that a value is a non-negative integer +`boolean($value, $message = '')` | Check that a value is a boolean +`scalar($value, $message = '')` | Check that a value is a scalar +`object($value, $message = '')` | Check that a value is an object +`resource($value, $type = null, $message = '')` | Check that a value is a resource +`isCallable($value, $message = '')` | Check that a value is a callable +`isArray($value, $message = '')` | Check that a value is an array +`isTraversable($value, $message = '')` (deprecated) | Check that a value is an array or a `\Traversable` +`isIterable($value, $message = '')` | Check that a value is an array or a `\Traversable` +`isCountable($value, $message = '')` | Check that a value is an array or a `\Countable` +`isInstanceOf($value, $class, $message = '')` | Check that a value is an `instanceof` a class +`isInstanceOfAny($value, array $classes, $message = '')` | Check that a value is an `instanceof` at least one class on the array of classes +`notInstanceOf($value, $class, $message = '')` | Check that a value is not an `instanceof` a class +`isAOf($value, $class, $message = '')` | Check that a value is of the class or has one of its parents +`isAnyOf($value, array $classes, $message = '')` | Check that a value is of at least one of the classes or has one of its parents +`isNotA($value, $class, $message = '')` | Check that a value is not of the class or has not one of its parents +`isArrayAccessible($value, $message = '')` | Check that a value can be accessed as an array +`uniqueValues($values, $message = '')` | Check that the given array contains unique values + +### Comparison Assertions + +Method | Description +----------------------------------------------- | ------------------------------------------------------------------ +`true($value, $message = '')` | Check that a value is `true` +`false($value, $message = '')` | Check that a value is `false` +`notFalse($value, $message = '')` | Check that a value is not `false` +`null($value, $message = '')` | Check that a value is `null` +`notNull($value, $message = '')` | Check that a value is not `null` +`isEmpty($value, $message = '')` | Check that a value is `empty()` +`notEmpty($value, $message = '')` | Check that a value is not `empty()` +`eq($value, $value2, $message = '')` | Check that a value equals another (`==`) +`notEq($value, $value2, $message = '')` | Check that a value does not equal another (`!=`) +`same($value, $value2, $message = '')` | Check that a value is identical to another (`===`) +`notSame($value, $value2, $message = '')` | Check that a value is not identical to another (`!==`) +`greaterThan($value, $value2, $message = '')` | Check that a value is greater than another +`greaterThanEq($value, $value2, $message = '')` | Check that a value is greater than or equal to another +`lessThan($value, $value2, $message = '')` | Check that a value is less than another +`lessThanEq($value, $value2, $message = '')` | Check that a value is less than or equal to another +`range($value, $min, $max, $message = '')` | Check that a value is within a range +`inArray($value, array $values, $message = '')` | Check that a value is one of a list of values +`oneOf($value, array $values, $message = '')` | Check that a value is one of a list of values (alias of `inArray`) + +### String Assertions + +You should check that a value is a string with `Assert::string()` before making +any of the following assertions. + +Method | Description +--------------------------------------------------- | ----------------------------------------------------------------- +`contains($value, $subString, $message = '')` | Check that a string contains a substring +`notContains($value, $subString, $message = '')` | Check that a string does not contain a substring +`startsWith($value, $prefix, $message = '')` | Check that a string has a prefix +`notStartsWith($value, $prefix, $message = '')` | Check that a string does not have a prefix +`startsWithLetter($value, $message = '')` | Check that a string starts with a letter +`endsWith($value, $suffix, $message = '')` | Check that a string has a suffix +`notEndsWith($value, $suffix, $message = '')` | Check that a string does not have a suffix +`regex($value, $pattern, $message = '')` | Check that a string matches a regular expression +`notRegex($value, $pattern, $message = '')` | Check that a string does not match a regular expression +`unicodeLetters($value, $message = '')` | Check that a string contains Unicode letters only +`alpha($value, $message = '')` | Check that a string contains letters only +`digits($value, $message = '')` | Check that a string contains digits only +`alnum($value, $message = '')` | Check that a string contains letters and digits only +`lower($value, $message = '')` | Check that a string contains lowercase characters only +`upper($value, $message = '')` | Check that a string contains uppercase characters only +`length($value, $length, $message = '')` | Check that a string has a certain number of characters +`minLength($value, $min, $message = '')` | Check that a string has at least a certain number of characters +`maxLength($value, $max, $message = '')` | Check that a string has at most a certain number of characters +`lengthBetween($value, $min, $max, $message = '')` | Check that a string has a length in the given range +`uuid($value, $message = '')` | Check that a string is a valid UUID +`ip($value, $message = '')` | Check that a string is a valid IP (either IPv4 or IPv6) +`ipv4($value, $message = '')` | Check that a string is a valid IPv4 +`ipv6($value, $message = '')` | Check that a string is a valid IPv6 +`email($value, $message = '')` | Check that a string is a valid e-mail address +`notWhitespaceOnly($value, $message = '')` | Check that a string contains at least one non-whitespace character + +### File Assertions + +Method | Description +----------------------------------- | -------------------------------------------------- +`fileExists($value, $message = '')` | Check that a value is an existing path +`file($value, $message = '')` | Check that a value is an existing file +`directory($value, $message = '')` | Check that a value is an existing directory +`readable($value, $message = '')` | Check that a value is a readable path +`writable($value, $message = '')` | Check that a value is a writable path + +### Object Assertions + +Method | Description +----------------------------------------------------- | -------------------------------------------------- +`classExists($value, $message = '')` | Check that a value is an existing class name +`subclassOf($value, $class, $message = '')` | Check that a class is a subclass of another +`interfaceExists($value, $message = '')` | Check that a value is an existing interface name +`implementsInterface($value, $class, $message = '')` | Check that a class implements an interface +`propertyExists($value, $property, $message = '')` | Check that a property exists in a class/object +`propertyNotExists($value, $property, $message = '')` | Check that a property does not exist in a class/object +`methodExists($value, $method, $message = '')` | Check that a method exists in a class/object +`methodNotExists($value, $method, $message = '')` | Check that a method does not exist in a class/object + +### Array Assertions + +Method | Description +-------------------------------------------------- | ------------------------------------------------------------------ +`keyExists($array, $key, $message = '')` | Check that a key exists in an array +`keyNotExists($array, $key, $message = '')` | Check that a key does not exist in an array +`validArrayKey($key, $message = '')` | Check that a value is a valid array key (int or string) +`count($array, $number, $message = '')` | Check that an array contains a specific number of elements +`minCount($array, $min, $message = '')` | Check that an array contains at least a certain number of elements +`maxCount($array, $max, $message = '')` | Check that an array contains at most a certain number of elements +`countBetween($array, $min, $max, $message = '')` | Check that an array has a count in the given range +`isList($array, $message = '')` | Check that an array is a non-associative list +`isNonEmptyList($array, $message = '')` | Check that an array is a non-associative list, and not empty +`isMap($array, $message = '')` | Check that an array is associative and has strings as keys +`isNonEmptyMap($array, $message = '')` | Check that an array is associative and has strings as keys, and is not empty + +### Function Assertions + +Method | Description +------------------------------------------- | ----------------------------------------------------------------------------------------------------- +`throws($closure, $class, $message = '')` | Check that a function throws a certain exception. Subclasses of the exception class will be accepted. + +### Collection Assertions + +All of the above assertions can be prefixed with `all*()` to test the contents +of an array or a `\Traversable`: + +```php +Assert::allIsInstanceOf($employees, 'Acme\Employee'); +``` + +### Nullable Assertions + +All of the above assertions can be prefixed with `nullOr*()` to run the +assertion only if it the value is not `null`: + +```php +Assert::nullOrString($middleName, 'The middle name must be a string or null. Got: %s'); +``` + +### Extending Assert + +The `Assert` class comes with a few methods, which can be overridden to change the class behaviour. You can also extend it to +add your own assertions. + +#### Overriding methods + +Overriding the following methods in your assertion class allows you to change the behaviour of the assertions: + +* `public static function __callStatic($name, $arguments)` + * This method is used to 'create' the `nullOr` and `all` versions of the assertions. +* `protected static function valueToString($value)` + * This method is used for error messages, to convert the value to a string value for displaying. You could use this for representing a value object with a `__toString` method for example. +* `protected static function typeToString($value)` + * This method is used for error messages, to convert the a value to a string representing its type. +* `protected static function strlen($value)` + * This method is used to calculate string length for relevant methods, using the `mb_strlen` if available and useful. +* `protected static function reportInvalidArgument($message)` + * This method is called when an assertion fails, with the specified error message. Here you can throw your own exception, or log something. + +## Static analysis support + +Where applicable, assertion functions are annotated to support Psalm's +[Assertion syntax](https://psalm.dev/docs/annotating_code/assertion_syntax/). +A dedicated [PHPStan Plugin](https://github.com/phpstan/phpstan-webmozart-assert) is +required for proper type support. + +Authors +------- + +* [Bernhard Schussek] a.k.a. [@webmozart] +* [The Community Contributors] + +Contribute +---------- + +Contributions to the package are always welcome! + +* Report any bugs or issues you find on the [issue tracker]. +* You can grab the source code at the package's [Git repository]. + +License +------- + +All contents of this package are licensed under the [MIT license]. + +[beberlei/assert]: https://github.com/beberlei/assert +[assert package]: https://github.com/beberlei/assert +[Composer]: https://getcomposer.org +[Bernhard Schussek]: https://webmozarts.com +[The Community Contributors]: https://github.com/webmozart/assert/graphs/contributors +[issue tracker]: https://github.com/webmozart/assert/issues +[Git repository]: https://github.com/webmozart/assert +[@webmozart]: https://twitter.com/webmozart +[MIT license]: LICENSE +[`Assert`]: src/Assert.php diff --git a/vendor/webmozart/assert/composer.json b/vendor/webmozart/assert/composer.json new file mode 100644 index 000000000..b340452c7 --- /dev/null +++ b/vendor/webmozart/assert/composer.json @@ -0,0 +1,43 @@ +{ + "name": "webmozart/assert", + "description": "Assertions to validate method input/output with nice error messages.", + "license": "MIT", + "keywords": [ + "assert", + "check", + "validate" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "require": { + "php": "^7.2 || ^8.0", + "ext-ctype": "*" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Webmozart\\Assert\\Tests\\": "tests/", + "Webmozart\\Assert\\Bin\\": "bin/src" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + } +} diff --git a/vendor/webmozart/assert/src/Assert.php b/vendor/webmozart/assert/src/Assert.php new file mode 100644 index 000000000..db1f3a51a --- /dev/null +++ b/vendor/webmozart/assert/src/Assert.php @@ -0,0 +1,2080 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Webmozart\Assert; + +use ArrayAccess; +use BadMethodCallException; +use Closure; +use Countable; +use DateTime; +use DateTimeImmutable; +use Exception; +use ResourceBundle; +use SimpleXMLElement; +use Throwable; +use Traversable; + +/** + * Efficient assertions to validate the input/output of your methods. + * + * @since 1.0 + * + * @author Bernhard Schussek + */ +class Assert +{ + use Mixin; + + /** + * @psalm-pure + * @psalm-assert string $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function string($value, $message = '') + { + if (!\is_string($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a string. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert non-empty-string $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function stringNotEmpty($value, $message = '') + { + static::string($value, $message); + static::notEq($value, '', $message); + } + + /** + * @psalm-pure + * @psalm-assert int $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function integer($value, $message = '') + { + if (!\is_int($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an integer. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert numeric $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function integerish($value, $message = '') + { + if (!\is_numeric($value) || $value != (int) $value) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an integerish value. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert positive-int $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function positiveInteger($value, $message = '') + { + if (!(\is_int($value) && $value > 0)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a positive integer. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert float $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function float($value, $message = '') + { + if (!\is_float($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a float. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert numeric $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function numeric($value, $message = '') + { + if (!\is_numeric($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a numeric. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert positive-int|0 $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function natural($value, $message = '') + { + if (!\is_int($value) || $value < 0) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a non-negative integer. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert bool $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function boolean($value, $message = '') + { + if (!\is_bool($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a boolean. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert scalar $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function scalar($value, $message = '') + { + if (!\is_scalar($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a scalar. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert object $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function object($value, $message = '') + { + if (!\is_object($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an object. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert resource $value + * + * @param mixed $value + * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function resource($value, $type = null, $message = '') + { + if (!\is_resource($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a resource. Got: %s', + static::typeToString($value) + )); + } + + if ($type && $type !== \get_resource_type($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a resource of type %2$s. Got: %s', + static::typeToString($value), + $type + )); + } + } + + /** + * @psalm-pure + * @psalm-assert callable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isCallable($value, $message = '') + { + if (!\is_callable($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a callable. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert array $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isArray($value, $message = '') + { + if (!\is_array($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an array. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @deprecated use "isIterable" or "isInstanceOf" instead + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isTraversable($value, $message = '') + { + @\trigger_error( + \sprintf( + 'The "%s" assertion is deprecated. You should stop using it, as it will soon be removed in 2.0 version. Use "isIterable" or "isInstanceOf" instead.', + __METHOD__ + ), + \E_USER_DEPRECATED + ); + + if (!\is_array($value) && !($value instanceof Traversable)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a traversable. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert array|ArrayAccess $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isArrayAccessible($value, $message = '') + { + if (!\is_array($value) && !($value instanceof ArrayAccess)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an array accessible. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert countable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isCountable($value, $message = '') + { + if ( + !\is_array($value) + && !($value instanceof Countable) + && !($value instanceof ResourceBundle) + && !($value instanceof SimpleXMLElement) + ) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a countable. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isIterable($value, $message = '') + { + if (!\is_array($value) && !($value instanceof Traversable)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an iterable. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert ExpectedType $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isInstanceOf($value, $class, $message = '') + { + if (!($value instanceof $class)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an instance of %2$s. Got: %s', + static::typeToString($value), + $class + )); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert !ExpectedType $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notInstanceOf($value, $class, $message = '') + { + if ($value instanceof $class) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an instance other than %2$s. Got: %s', + static::typeToString($value), + $class + )); + } + } + + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param mixed $value + * @param array $classes + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isInstanceOfAny($value, array $classes, $message = '') + { + foreach ($classes as $class) { + if ($value instanceof $class) { + return; + } + } + + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an instance of any of %2$s. Got: %s', + static::typeToString($value), + \implode(', ', \array_map(array(static::class, 'valueToString'), $classes)) + )); + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert ExpectedType|class-string $value + * + * @param object|string $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isAOf($value, $class, $message = '') + { + static::string($class, 'Expected class as a string. Got: %s'); + + if (!\is_a($value, $class, \is_string($value))) { + static::reportInvalidArgument(sprintf( + $message ?: 'Expected an instance of this class or to this class among its parents "%2$s". Got: %s', + static::valueToString($value), + $class + )); + } + } + + /** + * @psalm-pure + * @psalm-template UnexpectedType of object + * @psalm-param class-string $class + * @psalm-assert !UnexpectedType $value + * @psalm-assert !class-string $value + * + * @param object|string $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isNotA($value, $class, $message = '') + { + static::string($class, 'Expected class as a string. Got: %s'); + + if (\is_a($value, $class, \is_string($value))) { + static::reportInvalidArgument(sprintf( + $message ?: 'Expected an instance of this class or to this class among its parents other than "%2$s". Got: %s', + static::valueToString($value), + $class + )); + } + } + + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param object|string $value + * @param string[] $classes + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isAnyOf($value, array $classes, $message = '') + { + foreach ($classes as $class) { + static::string($class, 'Expected class as a string. Got: %s'); + + if (\is_a($value, $class, \is_string($value))) { + return; + } + } + + static::reportInvalidArgument(sprintf( + $message ?: 'Expected an instance of any of this classes or any of those classes among their parents "%2$s". Got: %s', + static::valueToString($value), + \implode(', ', $classes) + )); + } + + /** + * @psalm-pure + * @psalm-assert empty $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isEmpty($value, $message = '') + { + if (!empty($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an empty value. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert !empty $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notEmpty($value, $message = '') + { + if (empty($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a non-empty value. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function null($value, $message = '') + { + if (null !== $value) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected null. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert !null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notNull($value, $message = '') + { + if (null === $value) { + static::reportInvalidArgument( + $message ?: 'Expected a value other than null.' + ); + } + } + + /** + * @psalm-pure + * @psalm-assert true $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function true($value, $message = '') + { + if (true !== $value) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to be true. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert false $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function false($value, $message = '') + { + if (false !== $value) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to be false. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert !false $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notFalse($value, $message = '') + { + if (false === $value) { + static::reportInvalidArgument( + $message ?: 'Expected a value other than false.' + ); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function ip($value, $message = '') + { + if (false === \filter_var($value, \FILTER_VALIDATE_IP)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to be an IP. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function ipv4($value, $message = '') + { + if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to be an IPv4. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function ipv6($value, $message = '') + { + if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to be an IPv6. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function email($value, $message = '') + { + if (false === \filter_var($value, FILTER_VALIDATE_EMAIL)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to be a valid e-mail address. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * Does non strict comparisons on the items, so ['3', 3] will not pass the assertion. + * + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function uniqueValues(array $values, $message = '') + { + $allValues = \count($values); + $uniqueValues = \count(\array_unique($values)); + + if ($allValues !== $uniqueValues) { + $difference = $allValues - $uniqueValues; + + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an array of unique values, but %s of them %s duplicated', + $difference, + (1 === $difference ? 'is' : 'are') + )); + } + } + + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function eq($value, $expect, $message = '') + { + if ($expect != $value) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value equal to %2$s. Got: %s', + static::valueToString($value), + static::valueToString($expect) + )); + } + } + + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notEq($value, $expect, $message = '') + { + if ($expect == $value) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a different value than %s.', + static::valueToString($expect) + )); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function same($value, $expect, $message = '') + { + if ($expect !== $value) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value identical to %2$s. Got: %s', + static::valueToString($value), + static::valueToString($expect) + )); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notSame($value, $expect, $message = '') + { + if ($expect === $value) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value not identical to %s.', + static::valueToString($expect) + )); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function greaterThan($value, $limit, $message = '') + { + if ($value <= $limit) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value greater than %2$s. Got: %s', + static::valueToString($value), + static::valueToString($limit) + )); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function greaterThanEq($value, $limit, $message = '') + { + if ($value < $limit) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value greater than or equal to %2$s. Got: %s', + static::valueToString($value), + static::valueToString($limit) + )); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function lessThan($value, $limit, $message = '') + { + if ($value >= $limit) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value less than %2$s. Got: %s', + static::valueToString($value), + static::valueToString($limit) + )); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function lessThanEq($value, $limit, $message = '') + { + if ($value > $limit) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value less than or equal to %2$s. Got: %s', + static::valueToString($value), + static::valueToString($limit) + )); + } + } + + /** + * Inclusive range, so Assert::(3, 3, 5) passes. + * + * @psalm-pure + * + * @param mixed $value + * @param mixed $min + * @param mixed $max + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function range($value, $min, $max, $message = '') + { + if ($value < $min || $value > $max) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value between %2$s and %3$s. Got: %s', + static::valueToString($value), + static::valueToString($min), + static::valueToString($max) + )); + } + } + + /** + * A more human-readable alias of Assert::inArray(). + * + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function oneOf($value, array $values, $message = '') + { + static::inArray($value, $values, $message); + } + + /** + * Does strict comparison, so Assert::inArray(3, ['3']) does not pass the assertion. + * + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function inArray($value, array $values, $message = '') + { + if (!\in_array($value, $values, true)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected one of: %2$s. Got: %s', + static::valueToString($value), + \implode(', ', \array_map(array(static::class, 'valueToString'), $values)) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function contains($value, $subString, $message = '') + { + if (false === \strpos($value, $subString)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain %2$s. Got: %s', + static::valueToString($value), + static::valueToString($subString) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notContains($value, $subString, $message = '') + { + if (false !== \strpos($value, $subString)) { + static::reportInvalidArgument(\sprintf( + $message ?: '%2$s was not expected to be contained in a value. Got: %s', + static::valueToString($value), + static::valueToString($subString) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notWhitespaceOnly($value, $message = '') + { + if (\preg_match('/^\s*$/', $value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a non-whitespace string. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function startsWith($value, $prefix, $message = '') + { + if (0 !== \strpos($value, $prefix)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to start with %2$s. Got: %s', + static::valueToString($value), + static::valueToString($prefix) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notStartsWith($value, $prefix, $message = '') + { + if (0 === \strpos($value, $prefix)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value not to start with %2$s. Got: %s', + static::valueToString($value), + static::valueToString($prefix) + )); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function startsWithLetter($value, $message = '') + { + static::string($value); + + $valid = isset($value[0]); + + if ($valid) { + $locale = \setlocale(LC_CTYPE, 0); + \setlocale(LC_CTYPE, 'C'); + $valid = \ctype_alpha($value[0]); + \setlocale(LC_CTYPE, $locale); + } + + if (!$valid) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to start with a letter. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function endsWith($value, $suffix, $message = '') + { + if ($suffix !== \substr($value, -\strlen($suffix))) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to end with %2$s. Got: %s', + static::valueToString($value), + static::valueToString($suffix) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notEndsWith($value, $suffix, $message = '') + { + if ($suffix === \substr($value, -\strlen($suffix))) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value not to end with %2$s. Got: %s', + static::valueToString($value), + static::valueToString($suffix) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function regex($value, $pattern, $message = '') + { + if (!\preg_match($pattern, $value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'The value %s does not match the expected pattern.', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notRegex($value, $pattern, $message = '') + { + if (\preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'The value %s matches the pattern %s (at offset %d).', + static::valueToString($value), + static::valueToString($pattern), + $matches[0][1] + )); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function unicodeLetters($value, $message = '') + { + static::string($value); + + if (!\preg_match('/^\p{L}+$/u', $value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain only Unicode letters. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function alpha($value, $message = '') + { + static::string($value); + + $locale = \setlocale(LC_CTYPE, 0); + \setlocale(LC_CTYPE, 'C'); + $valid = !\ctype_alpha($value); + \setlocale(LC_CTYPE, $locale); + + if ($valid) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain only letters. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function digits($value, $message = '') + { + $locale = \setlocale(LC_CTYPE, 0); + \setlocale(LC_CTYPE, 'C'); + $valid = !\ctype_digit($value); + \setlocale(LC_CTYPE, $locale); + + if ($valid) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain digits only. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function alnum($value, $message = '') + { + $locale = \setlocale(LC_CTYPE, 0); + \setlocale(LC_CTYPE, 'C'); + $valid = !\ctype_alnum($value); + \setlocale(LC_CTYPE, $locale); + + if ($valid) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain letters and digits only. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert lowercase-string $value + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function lower($value, $message = '') + { + $locale = \setlocale(LC_CTYPE, 0); + \setlocale(LC_CTYPE, 'C'); + $valid = !\ctype_lower($value); + \setlocale(LC_CTYPE, $locale); + + if ($valid) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain lowercase characters only. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-assert !lowercase-string $value + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function upper($value, $message = '') + { + $locale = \setlocale(LC_CTYPE, 0); + \setlocale(LC_CTYPE, 'C'); + $valid = !\ctype_upper($value); + \setlocale(LC_CTYPE, $locale); + + if ($valid) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain uppercase characters only. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * + * @param string $value + * @param int $length + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function length($value, $length, $message = '') + { + if ($length !== static::strlen($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain %2$s characters. Got: %s', + static::valueToString($value), + $length + )); + } + } + + /** + * Inclusive min. + * + * @psalm-pure + * + * @param string $value + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function minLength($value, $min, $message = '') + { + if (static::strlen($value) < $min) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain at least %2$s characters. Got: %s', + static::valueToString($value), + $min + )); + } + } + + /** + * Inclusive max. + * + * @psalm-pure + * + * @param string $value + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function maxLength($value, $max, $message = '') + { + if (static::strlen($value) > $max) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain at most %2$s characters. Got: %s', + static::valueToString($value), + $max + )); + } + } + + /** + * Inclusive , so Assert::lengthBetween('asd', 3, 5); passes the assertion. + * + * @psalm-pure + * + * @param string $value + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function lengthBetween($value, $min, $max, $message = '') + { + $length = static::strlen($value); + + if ($length < $min || $length > $max) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s', + static::valueToString($value), + $min, + $max + )); + } + } + + /** + * Will also pass if $value is a directory, use Assert::file() instead if you need to be sure it is a file. + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function fileExists($value, $message = '') + { + static::string($value); + + if (!\file_exists($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'The file %s does not exist.', + static::valueToString($value) + )); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function file($value, $message = '') + { + static::fileExists($value, $message); + + if (!\is_file($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'The path %s is not a file.', + static::valueToString($value) + )); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function directory($value, $message = '') + { + static::fileExists($value, $message); + + if (!\is_dir($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'The path %s is no directory.', + static::valueToString($value) + )); + } + } + + /** + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function readable($value, $message = '') + { + if (!\is_readable($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'The path %s is not readable.', + static::valueToString($value) + )); + } + } + + /** + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function writable($value, $message = '') + { + if (!\is_writable($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'The path %s is not writable.', + static::valueToString($value) + )); + } + } + + /** + * @psalm-assert class-string $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function classExists($value, $message = '') + { + if (!\class_exists($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an existing class name. Got: %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert class-string|ExpectedType $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function subclassOf($value, $class, $message = '') + { + if (!\is_subclass_of($value, $class)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a sub-class of %2$s. Got: %s', + static::valueToString($value), + static::valueToString($class) + )); + } + } + + /** + * @psalm-assert class-string $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function interfaceExists($value, $message = '') + { + if (!\interface_exists($value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an existing interface name. got %s', + static::valueToString($value) + )); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $interface + * @psalm-assert class-string $value + * + * @param mixed $value + * @param mixed $interface + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function implementsInterface($value, $interface, $message = '') + { + if (!\in_array($interface, \class_implements($value))) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an implementation of %2$s. Got: %s', + static::valueToString($value), + static::valueToString($interface) + )); + } + } + + /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * + * @param string|object $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function propertyExists($classOrObject, $property, $message = '') + { + if (!\property_exists($classOrObject, $property)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected the property %s to exist.', + static::valueToString($property) + )); + } + } + + /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * + * @param string|object $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function propertyNotExists($classOrObject, $property, $message = '') + { + if (\property_exists($classOrObject, $property)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected the property %s to not exist.', + static::valueToString($property) + )); + } + } + + /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * + * @param string|object $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function methodExists($classOrObject, $method, $message = '') + { + if (!(\is_string($classOrObject) || \is_object($classOrObject)) || !\method_exists($classOrObject, $method)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected the method %s to exist.', + static::valueToString($method) + )); + } + } + + /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * + * @param string|object $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function methodNotExists($classOrObject, $method, $message = '') + { + if ((\is_string($classOrObject) || \is_object($classOrObject)) && \method_exists($classOrObject, $method)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected the method %s to not exist.', + static::valueToString($method) + )); + } + } + + /** + * @psalm-pure + * + * @param array $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function keyExists($array, $key, $message = '') + { + if (!(isset($array[$key]) || \array_key_exists($key, $array))) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected the key %s to exist.', + static::valueToString($key) + )); + } + } + + /** + * @psalm-pure + * + * @param array $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function keyNotExists($array, $key, $message = '') + { + if (isset($array[$key]) || \array_key_exists($key, $array)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected the key %s to not exist.', + static::valueToString($key) + )); + } + } + + /** + * Checks if a value is a valid array key (int or string). + * + * @psalm-pure + * @psalm-assert array-key $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function validArrayKey($value, $message = '') + { + if (!(\is_int($value) || \is_string($value))) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected string or integer. Got: %s', + static::typeToString($value) + )); + } + } + + /** + * Does not check if $array is countable, this can generate a warning on php versions after 7.2. + * + * @param Countable|array $array + * @param int $number + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function count($array, $number, $message = '') + { + static::eq( + \count($array), + $number, + \sprintf( + $message ?: 'Expected an array to contain %d elements. Got: %d.', + $number, + \count($array) + ) + ); + } + + /** + * Does not check if $array is countable, this can generate a warning on php versions after 7.2. + * + * @param Countable|array $array + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function minCount($array, $min, $message = '') + { + if (\count($array) < $min) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an array to contain at least %2$d elements. Got: %d', + \count($array), + $min + )); + } + } + + /** + * Does not check if $array is countable, this can generate a warning on php versions after 7.2. + * + * @param Countable|array $array + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function maxCount($array, $max, $message = '') + { + if (\count($array) > $max) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an array to contain at most %2$d elements. Got: %d', + \count($array), + $max + )); + } + } + + /** + * Does not check if $array is countable, this can generate a warning on php versions after 7.2. + * + * @param Countable|array $array + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function countBetween($array, $min, $max, $message = '') + { + $count = \count($array); + + if ($count < $min || $count > $max) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d', + $count, + $min, + $max + )); + } + } + + /** + * @psalm-pure + * @psalm-assert list $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isList($array, $message = '') + { + if (!\is_array($array)) { + static::reportInvalidArgument( + $message ?: 'Expected list - non-associative array.' + ); + } + + if ($array === \array_values($array)) { + return; + } + + $nextKey = -1; + foreach ($array as $k => $v) { + if ($k !== ++$nextKey) { + static::reportInvalidArgument( + $message ?: 'Expected list - non-associative array.' + ); + } + } + } + + /** + * @psalm-pure + * @psalm-assert non-empty-list $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isNonEmptyList($array, $message = '') + { + static::isList($array, $message); + static::notEmpty($array, $message); + } + + /** + * @psalm-pure + * @psalm-template T + * @psalm-param mixed|array $array + * @psalm-assert array $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isMap($array, $message = '') + { + if ( + !\is_array($array) || + \array_keys($array) !== \array_filter(\array_keys($array), '\is_string') + ) { + static::reportInvalidArgument( + $message ?: 'Expected map - associative array with string keys.' + ); + } + } + + /** + * @psalm-pure + * @psalm-template T + * @psalm-param mixed|array $array + * @psalm-assert array $array + * @psalm-assert !empty $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isNonEmptyMap($array, $message = '') + { + static::isMap($array, $message); + static::notEmpty($array, $message); + } + + /** + * @psalm-pure + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function uuid($value, $message = '') + { + $value = \str_replace(array('urn:', 'uuid:', '{', '}'), '', $value); + + // The nil UUID is special form of UUID that is specified to have all + // 128 bits set to zero. + if ('00000000-0000-0000-0000-000000000000' === $value) { + return; + } + + if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Value %s is not a valid UUID.', + static::valueToString($value) + )); + } + } + + /** + * @psalm-param class-string $class + * + * @param Closure $expression + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function throws(Closure $expression, $class = 'Exception', $message = '') + { + static::string($class); + + $actual = 'none'; + + try { + $expression(); + } catch (Exception $e) { + $actual = \get_class($e); + if ($e instanceof $class) { + return; + } + } catch (Throwable $e) { + $actual = \get_class($e); + if ($e instanceof $class) { + return; + } + } + + static::reportInvalidArgument($message ?: \sprintf( + 'Expected to throw "%s", got "%s"', + $class, + $actual + )); + } + + /** + * @throws BadMethodCallException + */ + public static function __callStatic($name, $arguments) + { + if ('nullOr' === \substr($name, 0, 6)) { + if (null !== $arguments[0]) { + $method = \lcfirst(\substr($name, 6)); + \call_user_func_array(array(static::class, $method), $arguments); + } + + return; + } + + if ('all' === \substr($name, 0, 3)) { + static::isIterable($arguments[0]); + + $method = \lcfirst(\substr($name, 3)); + $args = $arguments; + + foreach ($arguments[0] as $entry) { + $args[0] = $entry; + + \call_user_func_array(array(static::class, $method), $args); + } + + return; + } + + throw new BadMethodCallException('No such method: '.$name); + } + + /** + * @param mixed $value + * + * @return string + */ + protected static function valueToString($value) + { + if (null === $value) { + return 'null'; + } + + if (true === $value) { + return 'true'; + } + + if (false === $value) { + return 'false'; + } + + if (\is_array($value)) { + return 'array'; + } + + if (\is_object($value)) { + if (\method_exists($value, '__toString')) { + return \get_class($value).': '.self::valueToString($value->__toString()); + } + + if ($value instanceof DateTime || $value instanceof DateTimeImmutable) { + return \get_class($value).': '.self::valueToString($value->format('c')); + } + + return \get_class($value); + } + + if (\is_resource($value)) { + return 'resource'; + } + + if (\is_string($value)) { + return '"'.$value.'"'; + } + + return (string) $value; + } + + /** + * @param mixed $value + * + * @return string + */ + protected static function typeToString($value) + { + return \is_object($value) ? \get_class($value) : \gettype($value); + } + + protected static function strlen($value) + { + if (!\function_exists('mb_detect_encoding')) { + return \strlen($value); + } + + if (false === $encoding = \mb_detect_encoding($value)) { + return \strlen($value); + } + + return \mb_strlen($value, $encoding); + } + + /** + * @param string $message + * + * @throws InvalidArgumentException + * + * @psalm-pure this method is not supposed to perform side-effects + * @psalm-return never + */ + protected static function reportInvalidArgument($message) + { + throw new InvalidArgumentException($message); + } + + private function __construct() + { + } +} diff --git a/vendor/webmozart/assert/src/InvalidArgumentException.php b/vendor/webmozart/assert/src/InvalidArgumentException.php new file mode 100644 index 000000000..9d95a58c5 --- /dev/null +++ b/vendor/webmozart/assert/src/InvalidArgumentException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Webmozart\Assert; + +class InvalidArgumentException extends \InvalidArgumentException +{ +} diff --git a/vendor/webmozart/assert/src/Mixin.php b/vendor/webmozart/assert/src/Mixin.php new file mode 100644 index 000000000..0f0a75e33 --- /dev/null +++ b/vendor/webmozart/assert/src/Mixin.php @@ -0,0 +1,5089 @@ + $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allString($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::string($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrString($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::string($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert non-empty-string|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrStringNotEmpty($value, $message = '') + { + null === $value || static::stringNotEmpty($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allStringNotEmpty($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::stringNotEmpty($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrStringNotEmpty($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::stringNotEmpty($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert int|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrInteger($value, $message = '') + { + null === $value || static::integer($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allInteger($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::integer($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrInteger($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::integer($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert numeric|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIntegerish($value, $message = '') + { + null === $value || static::integerish($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIntegerish($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::integerish($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIntegerish($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::integerish($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert positive-int|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrPositiveInteger($value, $message = '') + { + null === $value || static::positiveInteger($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allPositiveInteger($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::positiveInteger($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrPositiveInteger($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::positiveInteger($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert float|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrFloat($value, $message = '') + { + null === $value || static::float($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allFloat($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::float($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrFloat($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::float($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert numeric|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNumeric($value, $message = '') + { + null === $value || static::numeric($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNumeric($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::numeric($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNumeric($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::numeric($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert positive-int|0|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNatural($value, $message = '') + { + null === $value || static::natural($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNatural($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::natural($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNatural($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::natural($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert bool|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrBoolean($value, $message = '') + { + null === $value || static::boolean($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allBoolean($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::boolean($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrBoolean($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::boolean($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert scalar|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrScalar($value, $message = '') + { + null === $value || static::scalar($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allScalar($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::scalar($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrScalar($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::scalar($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert object|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrObject($value, $message = '') + { + null === $value || static::object($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allObject($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::object($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrObject($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::object($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert resource|null $value + * + * @param mixed $value + * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrResource($value, $type = null, $message = '') + { + null === $value || static::resource($value, $type, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allResource($value, $type = null, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::resource($entry, $type, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrResource($value, $type = null, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::resource($entry, $type, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert callable|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsCallable($value, $message = '') + { + null === $value || static::isCallable($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsCallable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isCallable($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsCallable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isCallable($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert array|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsArray($value, $message = '') + { + null === $value || static::isArray($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsArray($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isArray($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsArray($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isArray($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable|null $value + * + * @deprecated use "isIterable" or "isInstanceOf" instead + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsTraversable($value, $message = '') + { + null === $value || static::isTraversable($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @deprecated use "isIterable" or "isInstanceOf" instead + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsTraversable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isTraversable($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @deprecated use "isIterable" or "isInstanceOf" instead + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsTraversable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isTraversable($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert array|ArrayAccess|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsArrayAccessible($value, $message = '') + { + null === $value || static::isArrayAccessible($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsArrayAccessible($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isArrayAccessible($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsArrayAccessible($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isArrayAccessible($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert countable|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsCountable($value, $message = '') + { + null === $value || static::isCountable($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsCountable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isCountable($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsCountable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isCountable($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsIterable($value, $message = '') + { + null === $value || static::isIterable($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsIterable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isIterable($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsIterable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isIterable($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert ExpectedType|null $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsInstanceOf($value, $class, $message = '') + { + null === $value || static::isInstanceOf($value, $class, $message); + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsInstanceOf($value, $class, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isInstanceOf($entry, $class, $message); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsInstanceOf($value, $class, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isInstanceOf($entry, $class, $message); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotInstanceOf($value, $class, $message = '') + { + null === $value || static::notInstanceOf($value, $class, $message); + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotInstanceOf($value, $class, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notInstanceOf($entry, $class, $message); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotInstanceOf($value, $class, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notInstanceOf($entry, $class, $message); + } + } + + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param mixed $value + * @param array $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsInstanceOfAny($value, $classes, $message = '') + { + null === $value || static::isInstanceOfAny($value, $classes, $message); + } + + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param mixed $value + * @param array $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsInstanceOfAny($value, $classes, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isInstanceOfAny($entry, $classes, $message); + } + } + + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param mixed $value + * @param array $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsInstanceOfAny($value, $classes, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isInstanceOfAny($entry, $classes, $message); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert ExpectedType|class-string|null $value + * + * @param object|string|null $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsAOf($value, $class, $message = '') + { + null === $value || static::isAOf($value, $class, $message); + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable> $value + * + * @param iterable $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsAOf($value, $class, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isAOf($entry, $class, $message); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable|null> $value + * + * @param iterable $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsAOf($value, $class, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isAOf($entry, $class, $message); + } + } + + /** + * @psalm-pure + * @psalm-template UnexpectedType of object + * @psalm-param class-string $class + * + * @param object|string|null $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsNotA($value, $class, $message = '') + { + null === $value || static::isNotA($value, $class, $message); + } + + /** + * @psalm-pure + * @psalm-template UnexpectedType of object + * @psalm-param class-string $class + * + * @param iterable $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsNotA($value, $class, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isNotA($entry, $class, $message); + } + } + + /** + * @psalm-pure + * @psalm-template UnexpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable $value + * @psalm-assert iterable|null> $value + * + * @param iterable $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsNotA($value, $class, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isNotA($entry, $class, $message); + } + } + + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param object|string|null $value + * @param string[] $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsAnyOf($value, $classes, $message = '') + { + null === $value || static::isAnyOf($value, $classes, $message); + } + + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param iterable $value + * @param string[] $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsAnyOf($value, $classes, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isAnyOf($entry, $classes, $message); + } + } + + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param iterable $value + * @param string[] $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsAnyOf($value, $classes, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isAnyOf($entry, $classes, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert empty $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsEmpty($value, $message = '') + { + null === $value || static::isEmpty($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsEmpty($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::isEmpty($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsEmpty($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::isEmpty($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotEmpty($value, $message = '') + { + null === $value || static::notEmpty($value, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotEmpty($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notEmpty($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotEmpty($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notEmpty($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNull($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::null($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotNull($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notNull($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert true|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrTrue($value, $message = '') + { + null === $value || static::true($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allTrue($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::true($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrTrue($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::true($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert false|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrFalse($value, $message = '') + { + null === $value || static::false($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allFalse($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::false($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrFalse($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::false($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotFalse($value, $message = '') + { + null === $value || static::notFalse($value, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotFalse($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notFalse($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotFalse($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notFalse($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIp($value, $message = '') + { + null === $value || static::ip($value, $message); + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIp($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::ip($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIp($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::ip($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIpv4($value, $message = '') + { + null === $value || static::ipv4($value, $message); + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIpv4($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::ipv4($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIpv4($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::ipv4($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIpv6($value, $message = '') + { + null === $value || static::ipv6($value, $message); + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIpv6($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::ipv6($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIpv6($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::ipv6($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrEmail($value, $message = '') + { + null === $value || static::email($value, $message); + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allEmail($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::email($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrEmail($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::email($entry, $message); + } + } + + /** + * @param array|null $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrUniqueValues($values, $message = '') + { + null === $values || static::uniqueValues($values, $message); + } + + /** + * @param iterable $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allUniqueValues($values, $message = '') + { + static::isIterable($values); + + foreach ($values as $entry) { + static::uniqueValues($entry, $message); + } + } + + /** + * @param iterable $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrUniqueValues($values, $message = '') + { + static::isIterable($values); + + foreach ($values as $entry) { + null === $entry || static::uniqueValues($entry, $message); + } + } + + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrEq($value, $expect, $message = '') + { + null === $value || static::eq($value, $expect, $message); + } + + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allEq($value, $expect, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::eq($entry, $expect, $message); + } + } + + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrEq($value, $expect, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::eq($entry, $expect, $message); + } + } + + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotEq($value, $expect, $message = '') + { + null === $value || static::notEq($value, $expect, $message); + } + + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotEq($value, $expect, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notEq($entry, $expect, $message); + } + } + + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotEq($value, $expect, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notEq($entry, $expect, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrSame($value, $expect, $message = '') + { + null === $value || static::same($value, $expect, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allSame($value, $expect, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::same($entry, $expect, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrSame($value, $expect, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::same($entry, $expect, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotSame($value, $expect, $message = '') + { + null === $value || static::notSame($value, $expect, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotSame($value, $expect, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notSame($entry, $expect, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotSame($value, $expect, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notSame($entry, $expect, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrGreaterThan($value, $limit, $message = '') + { + null === $value || static::greaterThan($value, $limit, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allGreaterThan($value, $limit, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::greaterThan($entry, $limit, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrGreaterThan($value, $limit, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::greaterThan($entry, $limit, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrGreaterThanEq($value, $limit, $message = '') + { + null === $value || static::greaterThanEq($value, $limit, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allGreaterThanEq($value, $limit, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::greaterThanEq($entry, $limit, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrGreaterThanEq($value, $limit, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::greaterThanEq($entry, $limit, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrLessThan($value, $limit, $message = '') + { + null === $value || static::lessThan($value, $limit, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allLessThan($value, $limit, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::lessThan($entry, $limit, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrLessThan($value, $limit, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::lessThan($entry, $limit, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrLessThanEq($value, $limit, $message = '') + { + null === $value || static::lessThanEq($value, $limit, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allLessThanEq($value, $limit, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::lessThanEq($entry, $limit, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrLessThanEq($value, $limit, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::lessThanEq($entry, $limit, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $min + * @param mixed $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrRange($value, $min, $max, $message = '') + { + null === $value || static::range($value, $min, $max, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $min + * @param mixed $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allRange($value, $min, $max, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::range($entry, $min, $max, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $min + * @param mixed $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrRange($value, $min, $max, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::range($entry, $min, $max, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrOneOf($value, $values, $message = '') + { + null === $value || static::oneOf($value, $values, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allOneOf($value, $values, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::oneOf($entry, $values, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrOneOf($value, $values, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::oneOf($entry, $values, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrInArray($value, $values, $message = '') + { + null === $value || static::inArray($value, $values, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allInArray($value, $values, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::inArray($entry, $values, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrInArray($value, $values, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::inArray($entry, $values, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrContains($value, $subString, $message = '') + { + null === $value || static::contains($value, $subString, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allContains($value, $subString, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::contains($entry, $subString, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrContains($value, $subString, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::contains($entry, $subString, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotContains($value, $subString, $message = '') + { + null === $value || static::notContains($value, $subString, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotContains($value, $subString, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notContains($entry, $subString, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotContains($value, $subString, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notContains($entry, $subString, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotWhitespaceOnly($value, $message = '') + { + null === $value || static::notWhitespaceOnly($value, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotWhitespaceOnly($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notWhitespaceOnly($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotWhitespaceOnly($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notWhitespaceOnly($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrStartsWith($value, $prefix, $message = '') + { + null === $value || static::startsWith($value, $prefix, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allStartsWith($value, $prefix, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::startsWith($entry, $prefix, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrStartsWith($value, $prefix, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::startsWith($entry, $prefix, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotStartsWith($value, $prefix, $message = '') + { + null === $value || static::notStartsWith($value, $prefix, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotStartsWith($value, $prefix, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notStartsWith($entry, $prefix, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotStartsWith($value, $prefix, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notStartsWith($entry, $prefix, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrStartsWithLetter($value, $message = '') + { + null === $value || static::startsWithLetter($value, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allStartsWithLetter($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::startsWithLetter($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrStartsWithLetter($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::startsWithLetter($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrEndsWith($value, $suffix, $message = '') + { + null === $value || static::endsWith($value, $suffix, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allEndsWith($value, $suffix, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::endsWith($entry, $suffix, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrEndsWith($value, $suffix, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::endsWith($entry, $suffix, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotEndsWith($value, $suffix, $message = '') + { + null === $value || static::notEndsWith($value, $suffix, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotEndsWith($value, $suffix, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notEndsWith($entry, $suffix, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotEndsWith($value, $suffix, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notEndsWith($entry, $suffix, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrRegex($value, $pattern, $message = '') + { + null === $value || static::regex($value, $pattern, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allRegex($value, $pattern, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::regex($entry, $pattern, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrRegex($value, $pattern, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::regex($entry, $pattern, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotRegex($value, $pattern, $message = '') + { + null === $value || static::notRegex($value, $pattern, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotRegex($value, $pattern, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notRegex($entry, $pattern, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotRegex($value, $pattern, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notRegex($entry, $pattern, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrUnicodeLetters($value, $message = '') + { + null === $value || static::unicodeLetters($value, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allUnicodeLetters($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::unicodeLetters($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrUnicodeLetters($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::unicodeLetters($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrAlpha($value, $message = '') + { + null === $value || static::alpha($value, $message); + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allAlpha($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::alpha($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrAlpha($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::alpha($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrDigits($value, $message = '') + { + null === $value || static::digits($value, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allDigits($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::digits($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrDigits($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::digits($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrAlnum($value, $message = '') + { + null === $value || static::alnum($value, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allAlnum($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::alnum($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrAlnum($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::alnum($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert lowercase-string|null $value + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrLower($value, $message = '') + { + null === $value || static::lower($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allLower($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::lower($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrLower($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::lower($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrUpper($value, $message = '') + { + null === $value || static::upper($value, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allUpper($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::upper($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrUpper($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::upper($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param int $length + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrLength($value, $length, $message = '') + { + null === $value || static::length($value, $length, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param int $length + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allLength($value, $length, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::length($entry, $length, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param int $length + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrLength($value, $length, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::length($entry, $length, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMinLength($value, $min, $message = '') + { + null === $value || static::minLength($value, $min, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMinLength($value, $min, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::minLength($entry, $min, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMinLength($value, $min, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::minLength($entry, $min, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMaxLength($value, $max, $message = '') + { + null === $value || static::maxLength($value, $max, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMaxLength($value, $max, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::maxLength($entry, $max, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMaxLength($value, $max, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::maxLength($entry, $max, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrLengthBetween($value, $min, $max, $message = '') + { + null === $value || static::lengthBetween($value, $min, $max, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allLengthBetween($value, $min, $max, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::lengthBetween($entry, $min, $max, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrLengthBetween($value, $min, $max, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::lengthBetween($entry, $min, $max, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrFileExists($value, $message = '') + { + null === $value || static::fileExists($value, $message); + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allFileExists($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::fileExists($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrFileExists($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::fileExists($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrFile($value, $message = '') + { + null === $value || static::file($value, $message); + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allFile($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::file($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrFile($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::file($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrDirectory($value, $message = '') + { + null === $value || static::directory($value, $message); + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allDirectory($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::directory($entry, $message); + } + } + + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrDirectory($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::directory($entry, $message); + } + } + + /** + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrReadable($value, $message = '') + { + null === $value || static::readable($value, $message); + } + + /** + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allReadable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::readable($entry, $message); + } + } + + /** + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrReadable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::readable($entry, $message); + } + } + + /** + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrWritable($value, $message = '') + { + null === $value || static::writable($value, $message); + } + + /** + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allWritable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::writable($entry, $message); + } + } + + /** + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrWritable($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::writable($entry, $message); + } + } + + /** + * @psalm-assert class-string|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrClassExists($value, $message = '') + { + null === $value || static::classExists($value, $message); + } + + /** + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allClassExists($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::classExists($entry, $message); + } + } + + /** + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrClassExists($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::classExists($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert class-string|ExpectedType|null $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrSubclassOf($value, $class, $message = '') + { + null === $value || static::subclassOf($value, $class, $message); + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable|ExpectedType> $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allSubclassOf($value, $class, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::subclassOf($entry, $class, $message); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable|ExpectedType|null> $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrSubclassOf($value, $class, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::subclassOf($entry, $class, $message); + } + } + + /** + * @psalm-assert class-string|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrInterfaceExists($value, $message = '') + { + null === $value || static::interfaceExists($value, $message); + } + + /** + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allInterfaceExists($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::interfaceExists($entry, $message); + } + } + + /** + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrInterfaceExists($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::interfaceExists($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $interface + * @psalm-assert class-string|null $value + * + * @param mixed $value + * @param mixed $interface + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrImplementsInterface($value, $interface, $message = '') + { + null === $value || static::implementsInterface($value, $interface, $message); + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $interface + * @psalm-assert iterable> $value + * + * @param mixed $value + * @param mixed $interface + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allImplementsInterface($value, $interface, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::implementsInterface($entry, $interface, $message); + } + } + + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $interface + * @psalm-assert iterable|null> $value + * + * @param mixed $value + * @param mixed $interface + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrImplementsInterface($value, $interface, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::implementsInterface($entry, $interface, $message); + } + } + + /** + * @psalm-pure + * @psalm-param class-string|object|null $classOrObject + * + * @param string|object|null $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrPropertyExists($classOrObject, $property, $message = '') + { + null === $classOrObject || static::propertyExists($classOrObject, $property, $message); + } + + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allPropertyExists($classOrObject, $property, $message = '') + { + static::isIterable($classOrObject); + + foreach ($classOrObject as $entry) { + static::propertyExists($entry, $property, $message); + } + } + + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrPropertyExists($classOrObject, $property, $message = '') + { + static::isIterable($classOrObject); + + foreach ($classOrObject as $entry) { + null === $entry || static::propertyExists($entry, $property, $message); + } + } + + /** + * @psalm-pure + * @psalm-param class-string|object|null $classOrObject + * + * @param string|object|null $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrPropertyNotExists($classOrObject, $property, $message = '') + { + null === $classOrObject || static::propertyNotExists($classOrObject, $property, $message); + } + + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allPropertyNotExists($classOrObject, $property, $message = '') + { + static::isIterable($classOrObject); + + foreach ($classOrObject as $entry) { + static::propertyNotExists($entry, $property, $message); + } + } + + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrPropertyNotExists($classOrObject, $property, $message = '') + { + static::isIterable($classOrObject); + + foreach ($classOrObject as $entry) { + null === $entry || static::propertyNotExists($entry, $property, $message); + } + } + + /** + * @psalm-pure + * @psalm-param class-string|object|null $classOrObject + * + * @param string|object|null $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMethodExists($classOrObject, $method, $message = '') + { + null === $classOrObject || static::methodExists($classOrObject, $method, $message); + } + + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMethodExists($classOrObject, $method, $message = '') + { + static::isIterable($classOrObject); + + foreach ($classOrObject as $entry) { + static::methodExists($entry, $method, $message); + } + } + + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMethodExists($classOrObject, $method, $message = '') + { + static::isIterable($classOrObject); + + foreach ($classOrObject as $entry) { + null === $entry || static::methodExists($entry, $method, $message); + } + } + + /** + * @psalm-pure + * @psalm-param class-string|object|null $classOrObject + * + * @param string|object|null $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMethodNotExists($classOrObject, $method, $message = '') + { + null === $classOrObject || static::methodNotExists($classOrObject, $method, $message); + } + + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMethodNotExists($classOrObject, $method, $message = '') + { + static::isIterable($classOrObject); + + foreach ($classOrObject as $entry) { + static::methodNotExists($entry, $method, $message); + } + } + + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMethodNotExists($classOrObject, $method, $message = '') + { + static::isIterable($classOrObject); + + foreach ($classOrObject as $entry) { + null === $entry || static::methodNotExists($entry, $method, $message); + } + } + + /** + * @psalm-pure + * + * @param array|null $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrKeyExists($array, $key, $message = '') + { + null === $array || static::keyExists($array, $key, $message); + } + + /** + * @psalm-pure + * + * @param iterable $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allKeyExists($array, $key, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + static::keyExists($entry, $key, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrKeyExists($array, $key, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + null === $entry || static::keyExists($entry, $key, $message); + } + } + + /** + * @psalm-pure + * + * @param array|null $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrKeyNotExists($array, $key, $message = '') + { + null === $array || static::keyNotExists($array, $key, $message); + } + + /** + * @psalm-pure + * + * @param iterable $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allKeyNotExists($array, $key, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + static::keyNotExists($entry, $key, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrKeyNotExists($array, $key, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + null === $entry || static::keyNotExists($entry, $key, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert array-key|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrValidArrayKey($value, $message = '') + { + null === $value || static::validArrayKey($value, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allValidArrayKey($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::validArrayKey($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrValidArrayKey($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::validArrayKey($entry, $message); + } + } + + /** + * @param Countable|array|null $array + * @param int $number + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrCount($array, $number, $message = '') + { + null === $array || static::count($array, $number, $message); + } + + /** + * @param iterable $array + * @param int $number + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allCount($array, $number, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + static::count($entry, $number, $message); + } + } + + /** + * @param iterable $array + * @param int $number + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrCount($array, $number, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + null === $entry || static::count($entry, $number, $message); + } + } + + /** + * @param Countable|array|null $array + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMinCount($array, $min, $message = '') + { + null === $array || static::minCount($array, $min, $message); + } + + /** + * @param iterable $array + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMinCount($array, $min, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + static::minCount($entry, $min, $message); + } + } + + /** + * @param iterable $array + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMinCount($array, $min, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + null === $entry || static::minCount($entry, $min, $message); + } + } + + /** + * @param Countable|array|null $array + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMaxCount($array, $max, $message = '') + { + null === $array || static::maxCount($array, $max, $message); + } + + /** + * @param iterable $array + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMaxCount($array, $max, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + static::maxCount($entry, $max, $message); + } + } + + /** + * @param iterable $array + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMaxCount($array, $max, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + null === $entry || static::maxCount($entry, $max, $message); + } + } + + /** + * @param Countable|array|null $array + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrCountBetween($array, $min, $max, $message = '') + { + null === $array || static::countBetween($array, $min, $max, $message); + } + + /** + * @param iterable $array + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allCountBetween($array, $min, $max, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + static::countBetween($entry, $min, $max, $message); + } + } + + /** + * @param iterable $array + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrCountBetween($array, $min, $max, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + null === $entry || static::countBetween($entry, $min, $max, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert list|null $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsList($array, $message = '') + { + null === $array || static::isList($array, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsList($array, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + static::isList($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsList($array, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + null === $entry || static::isList($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert non-empty-list|null $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsNonEmptyList($array, $message = '') + { + null === $array || static::isNonEmptyList($array, $message); + } + + /** + * @psalm-pure + * @psalm-assert iterable $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsNonEmptyList($array, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + static::isNonEmptyList($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-assert iterable $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsNonEmptyList($array, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + null === $entry || static::isNonEmptyList($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-template T + * @psalm-param mixed|array|null $array + * @psalm-assert array|null $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsMap($array, $message = '') + { + null === $array || static::isMap($array, $message); + } + + /** + * @psalm-pure + * @psalm-template T + * @psalm-param iterable> $array + * @psalm-assert iterable> $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsMap($array, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + static::isMap($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-template T + * @psalm-param iterable|null> $array + * @psalm-assert iterable|null> $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsMap($array, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + null === $entry || static::isMap($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-template T + * @psalm-param mixed|array|null $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsNonEmptyMap($array, $message = '') + { + null === $array || static::isNonEmptyMap($array, $message); + } + + /** + * @psalm-pure + * @psalm-template T + * @psalm-param iterable> $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsNonEmptyMap($array, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + static::isNonEmptyMap($entry, $message); + } + } + + /** + * @psalm-pure + * @psalm-template T + * @psalm-param iterable|null> $array + * @psalm-assert iterable|null> $array + * @psalm-assert iterable $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsNonEmptyMap($array, $message = '') + { + static::isIterable($array); + + foreach ($array as $entry) { + null === $entry || static::isNonEmptyMap($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrUuid($value, $message = '') + { + null === $value || static::uuid($value, $message); + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allUuid($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + static::uuid($entry, $message); + } + } + + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrUuid($value, $message = '') + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::uuid($entry, $message); + } + } + + /** + * @psalm-param class-string $class + * + * @param Closure|null $expression + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrThrows($expression, $class = 'Exception', $message = '') + { + null === $expression || static::throws($expression, $class, $message); + } + + /** + * @psalm-param class-string $class + * + * @param iterable $expression + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allThrows($expression, $class = 'Exception', $message = '') + { + static::isIterable($expression); + + foreach ($expression as $entry) { + static::throws($entry, $class, $message); + } + } + + /** + * @psalm-param class-string $class + * + * @param iterable $expression + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrThrows($expression, $class = 'Exception', $message = '') + { + static::isIterable($expression); + + foreach ($expression as $entry) { + null === $entry || static::throws($entry, $class, $message); + } + } +}