{"tag":"programowanie","articles":{"projects\/oursong-let-s-choose-our-song":{"key":"projects\/oursong-let-s-choose-our-song","type":"article","published":true,"meta":{"createdAt":"2017-12-25T00:38:58+01:00","publishedAt":"2017-12-25T00:33:00+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/oursong.eurovote.eu\/","displayUrl":null}],"category":"projects","subcategory":null,"slug":"oursong-let-s-choose-our-song"},"content":{"en":{"slug":"oursong-let-s-choose-our-song","title":"OurSong \u2022 Let\u0027s choose our song!","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022603\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAkCAYAAACaJFpUAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhElEQVRIiZWXW48cRxmGn6rq0\/ScdmfP6+Pasr2RA0bYkIOQIoyAIIE4SMAlEvwJFEWIn8AlcBP+ATdcAOIiikSEsAgRgQSvYsfr9SHrncPOoXu6u7qquBjvsOudxM4ntdSaqvre+qrrfd9vhLXWCSFwziGEIMsyOp0O9XodACHE9InjmE+LdncAJiGqTNZWq1WEEEfmiM+9\/Ir72qLkvlbc1j5KwNW6pVaJkM0ldjsd5poNiixle28fs3yWhw8eIpxFOAcLKzR\/8FPS0hBIyUoccHm+ylolYCnyyYzlUabZywo+Hmu8cT7GaY+2baDCmKzfZt8VMB7iD7psrKxSrYd4YcblhWVu3NlmN8vQKqLIxlSDACUgNxYLxJ7kYr3CfOgRSck+JQ3fQwlBw\/fwAAJPMiwjwjBkZOFG13BqcZ6fvfpV3vnnP3jxi1dZHN+l12mj4gYnHnV4e7tH2wZsNGM25JjyxDIAX2jV2JyLcc4hBcyFinXr2C9KxqXFE0BHS6wz5FoTBxJdgAsjtgcZr37nu\/h5nyRNOHt6nbgIqEtNpARv3R1wai4ifPAR15\/fRAqQwF6mETjW4oCqJ3HAYuiRGYtav\/jcL3vOo7AOz\/MYpynGlKz6OcnuXXof32e9EfKrP73DOdcBAautCmm\/w72B5e6jLiUeV659mZE27I4LPClo+IpQCZQU5MaRWwcCJEIx0gYRVvCaC8zNt1hZWmatEbE7KhHKY5wXbMxXuLk7oH1\/B18ZXl7L8VzJUj2mnyRsJwWPck2oJANt6BeGkbZ0spKxsYyNmeD89W9\/dwhASLyognKWMPApxinOWRpxRDX0ocyh1KA8wihA6JTeWFA6x0ALls5sIIUEIFKCQE6OsnQO6xzGgScEIs\/zIzwE8DzvCHecc9x4+03iWp3nr1w7NjYYDHDOoZQiCAIAtNaEYTjl8kH+Y4DOOdrtNk\/+ppSi0WgwHA5QykMpD3AIKREqxDqBA9p5lw\/2t1iK57i2+NyRHEIIjpbyODzPwxhDGIbUarUjY\/VaHanUkQqzEtLCkI\/2GfU6nCznqO8JWDyee+aR+r5Pt9vlozs7\/OXNt\/jjH37PzZs3wTmstdPFy8vLvPvuu+R5Pl0vpeTJfE+t0DnH3t4ev\/ntr\/ndG29QiWNKXbB26gybV77E1nvvcPvm+9OEWVGSFQYQBIEPCASWWsU\/fnqzALXWpFmGtpafv\/46J09vsPNwl\/fe3+KlF1\/g69\/6NvvdNjsfvg9AFEVYaemUu9xLdpC6hhuu85VLczjnng4ohCDPM775jev0en1Ori0RRiHddgcpBQuxYqV5mgtnTgJQlJZBotk3Bf2xRuoCvzCzUs8GlFLSnF\/Cbt\/hwYNH\/Ptf7yGkIpCOpHOfhXPrZIUhCv9vV2M3IvQU5+ILMK6wWCmeHRCgGtdIx5p00OHezn2KPOP8xec4sbJMFHiEvk8YTjgXedCqSQba4oQFz6JKfew4YaK1MyOOQj5\/5SqdTocz6y1CkTPq7XL54nnmalUkhnocAZAkCSoTrHpLnKotcGopJlqof5YKBYEvObu+yvd\/\/BO2b33A6XOXWGjNc2HjLGElRuuS\/nAITGgkpURKibEGgZidFhBFUTjgCG+sMZRm8tH3e11Gw8GUS845FpdXqVQqU7A0SUjHY6SUlGWJlBKlPFqt+eNKcxjoANgPAg4YVOoq6bCPcxYlJc5BvV7D94Pp\/H7m+O\/OCCEEgR+gPEEUOFqtZzzShw8fIqUEHM5Btdmi0WggpSRJEgaDIb7vT3edaslu6hN4Er+UJHlBHFqubBy\/NDPF+0m3yLIMYyxCTHT2wBEOKsyyDF2WRI\/dAT7ZLY5VKITgez\/8EeMiZzQa4QUBUgjATUABISWlLqlEIS+\/8AK\/eO01wiCAyTQ83ycMQ8qyfDalUdUYYw1xax4hPeYadcZZhrOTy5SmKVJ6yEqEEZK836YQAVGlMrlEaYq1dlrh4ZjJQ2MMxjr8IGSh2cCOUurCY96PcElOs9HECxTD0QgpBYVXJUkHaK2x1iKEQGs9K\/VsQKdLsAadZ4TOsra2zK0Pt7h1+yMCqVDGYq3FliXOWCQOKXw8pTDGYK09dg8+FXDU79PfazPs9tBIbm9tMRgM2dy8RFCrIQWMOl3S\/pBxmuKUoTQlWV5gjCHP8plg8Anf8PK1E7QurfKfP4\/xy5R6o05Z5OztPiAZpYTVECUdnrRIQIwSlFTAxKAd7jGtnhFwtXmJUIdsbvYQOmM4GHH9+ivUmzWMLpFKUVoo8oILF86jqnOYXveIwx9+PxwzWwxrLWVZPvbFnCRJprIWRRFxHE\/nBkFAng4YJjlBGBJFEVLKiWIdEocpD5\/cwUGSA3InowH37mxN+ees5cq1lwjDiVM453BSojyF7wcT9zcGO8OaZlb4pLYexM72LaKowtLK+rGxYbJPr9MnDCPmmk2MdVQq0bFW81ObqCcFfWl5DSnVkbEDFREiphpn1BvzKKVQj7s7daid\/EwVHh6bABzdzNPiSOdtjHnqilxbjJ3833OAc+B7EmsdQkyaqEqgUPKTjfcg\/geiigyZapzK0gAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/oursong_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022603\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA musical competition, in which the managers lead their countries every week to a fight for a title of the best song.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u00221005\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAkCAYAAACaJFpUAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhElEQVRIiZWXW48cRxmGn6rq0\/ScdmfP6+Pasr2RA0bYkIOQIoyAIIE4SMAlEvwJFEWIn8AlcBP+ATdcAOIiikSEsAgRgQSvYsfr9SHrncPOoXu6u7qquBjvsOudxM4ntdSaqvre+qrrfd9vhLXWCSFwziGEIMsyOp0O9XodACHE9InjmE+LdncAJiGqTNZWq1WEEEfmiM+9\/Ir72qLkvlbc1j5KwNW6pVaJkM0ldjsd5poNiixle28fs3yWhw8eIpxFOAcLKzR\/8FPS0hBIyUoccHm+ylolYCnyyYzlUabZywo+Hmu8cT7GaY+2baDCmKzfZt8VMB7iD7psrKxSrYd4YcblhWVu3NlmN8vQKqLIxlSDACUgNxYLxJ7kYr3CfOgRSck+JQ3fQwlBw\/fwAAJPMiwjwjBkZOFG13BqcZ6fvfpV3vnnP3jxi1dZHN+l12mj4gYnHnV4e7tH2wZsNGM25JjyxDIAX2jV2JyLcc4hBcyFinXr2C9KxqXFE0BHS6wz5FoTBxJdgAsjtgcZr37nu\/h5nyRNOHt6nbgIqEtNpARv3R1wai4ifPAR15\/fRAqQwF6mETjW4oCqJ3HAYuiRGYtav\/jcL3vOo7AOz\/MYpynGlKz6OcnuXXof32e9EfKrP73DOdcBAautCmm\/w72B5e6jLiUeV659mZE27I4LPClo+IpQCZQU5MaRWwcCJEIx0gYRVvCaC8zNt1hZWmatEbE7KhHKY5wXbMxXuLk7oH1\/B18ZXl7L8VzJUj2mnyRsJwWPck2oJANt6BeGkbZ0spKxsYyNmeD89W9\/dwhASLyognKWMPApxinOWRpxRDX0ocyh1KA8wihA6JTeWFA6x0ALls5sIIUEIFKCQE6OsnQO6xzGgScEIs\/zIzwE8DzvCHecc9x4+03iWp3nr1w7NjYYDHDOoZQiCAIAtNaEYTjl8kH+Y4DOOdrtNk\/+ppSi0WgwHA5QykMpD3AIKREqxDqBA9p5lw\/2t1iK57i2+NyRHEIIjpbyODzPwxhDGIbUarUjY\/VaHanUkQqzEtLCkI\/2GfU6nCznqO8JWDyee+aR+r5Pt9vlozs7\/OXNt\/jjH37PzZs3wTmstdPFy8vLvPvuu+R5Pl0vpeTJfE+t0DnH3t4ev\/ntr\/ndG29QiWNKXbB26gybV77E1nvvcPvm+9OEWVGSFQYQBIEPCASWWsU\/fnqzALXWpFmGtpafv\/46J09vsPNwl\/fe3+KlF1\/g69\/6NvvdNjsfvg9AFEVYaemUu9xLdpC6hhuu85VLczjnng4ohCDPM775jev0en1Ori0RRiHddgcpBQuxYqV5mgtnTgJQlJZBotk3Bf2xRuoCvzCzUs8GlFLSnF\/Cbt\/hwYNH\/Ptf7yGkIpCOpHOfhXPrZIUhCv9vV2M3IvQU5+ILMK6wWCmeHRCgGtdIx5p00OHezn2KPOP8xec4sbJMFHiEvk8YTjgXedCqSQba4oQFz6JKfew4YaK1MyOOQj5\/5SqdTocz6y1CkTPq7XL54nnmalUkhnocAZAkCSoTrHpLnKotcGopJlqof5YKBYEvObu+yvd\/\/BO2b33A6XOXWGjNc2HjLGElRuuS\/nAITGgkpURKibEGgZidFhBFUTjgCG+sMZRm8tH3e11Gw8GUS845FpdXqVQqU7A0SUjHY6SUlGWJlBKlPFqt+eNKcxjoANgPAg4YVOoq6bCPcxYlJc5BvV7D94Pp\/H7m+O\/OCCEEgR+gPEEUOFqtZzzShw8fIqUEHM5Btdmi0WggpSRJEgaDIb7vT3edaslu6hN4Er+UJHlBHFqubBy\/NDPF+0m3yLIMYyxCTHT2wBEOKsyyDF2WRI\/dAT7ZLY5VKITgez\/8EeMiZzQa4QUBUgjATUABISWlLqlEIS+\/8AK\/eO01wiCAyTQ83ycMQ8qyfDalUdUYYw1xax4hPeYadcZZhrOTy5SmKVJ6yEqEEZK836YQAVGlMrlEaYq1dlrh4ZjJQ2MMxjr8IGSh2cCOUurCY96PcElOs9HECxTD0QgpBYVXJUkHaK2x1iKEQGs9K\/VsQKdLsAadZ4TOsra2zK0Pt7h1+yMCqVDGYq3FliXOWCQOKXw8pTDGYK09dg8+FXDU79PfazPs9tBIbm9tMRgM2dy8RFCrIQWMOl3S\/pBxmuKUoTQlWV5gjCHP8plg8Anf8PK1E7QurfKfP4\/xy5R6o05Z5OztPiAZpYTVECUdnrRIQIwSlFTAxKAd7jGtnhFwtXmJUIdsbvYQOmM4GHH9+ivUmzWMLpFKUVoo8oILF86jqnOYXveIwx9+PxwzWwxrLWVZPvbFnCRJprIWRRFxHE\/nBkFAng4YJjlBGBJFEVLKiWIdEocpD5\/cwUGSA3InowH37mxN+ees5cq1lwjDiVM453BSojyF7wcT9zcGO8OaZlb4pLYexM72LaKowtLK+rGxYbJPr9MnDCPmmk2MdVQq0bFW81ObqCcFfWl5DSnVkbEDFREiphpn1BvzKKVQj7s7daid\/EwVHh6bABzdzNPiSOdtjHnqilxbjJ3833OAc+B7EmsdQkyaqEqgUPKTjfcg\/geiigyZapzK0gAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u00221005\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA musical competition, in which the managers lead their countries every week to a fight for a title of the best song.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["competition","esc","eurovision","facebook","javascript","micrus","music","php","song","voting","websockets"],"hasMore":false,"image":"https:\/\/avris.it\/image\/oursong_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022301.5\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA musical competition, in which the managers lead their countries every week to a fight for a title of the best song.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022301.5\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA musical competition, in which the managers lead their countries every week to a fight for a title of the best song.\u003C\/p\u003E","words":22,"readTime":null,"lang":"en"},"pl":{"slug":"oursong-wybierzmy-nasz\u0105-piosenk\u0119","title":"OurSong \u2022 Wybierzmy nasz\u0105 piosenk\u0119!","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022603\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAkCAYAAACaJFpUAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhElEQVRIiZWXW48cRxmGn6rq0\/ScdmfP6+Pasr2RA0bYkIOQIoyAIIE4SMAlEvwJFEWIn8AlcBP+ATdcAOIiikSEsAgRgQSvYsfr9SHrncPOoXu6u7qquBjvsOudxM4ntdSaqvre+qrrfd9vhLXWCSFwziGEIMsyOp0O9XodACHE9InjmE+LdncAJiGqTNZWq1WEEEfmiM+9\/Ir72qLkvlbc1j5KwNW6pVaJkM0ldjsd5poNiixle28fs3yWhw8eIpxFOAcLKzR\/8FPS0hBIyUoccHm+ylolYCnyyYzlUabZywo+Hmu8cT7GaY+2baDCmKzfZt8VMB7iD7psrKxSrYd4YcblhWVu3NlmN8vQKqLIxlSDACUgNxYLxJ7kYr3CfOgRSck+JQ3fQwlBw\/fwAAJPMiwjwjBkZOFG13BqcZ6fvfpV3vnnP3jxi1dZHN+l12mj4gYnHnV4e7tH2wZsNGM25JjyxDIAX2jV2JyLcc4hBcyFinXr2C9KxqXFE0BHS6wz5FoTBxJdgAsjtgcZr37nu\/h5nyRNOHt6nbgIqEtNpARv3R1wai4ifPAR15\/fRAqQwF6mETjW4oCqJ3HAYuiRGYtav\/jcL3vOo7AOz\/MYpynGlKz6OcnuXXof32e9EfKrP73DOdcBAautCmm\/w72B5e6jLiUeV659mZE27I4LPClo+IpQCZQU5MaRWwcCJEIx0gYRVvCaC8zNt1hZWmatEbE7KhHKY5wXbMxXuLk7oH1\/B18ZXl7L8VzJUj2mnyRsJwWPck2oJANt6BeGkbZ0spKxsYyNmeD89W9\/dwhASLyognKWMPApxinOWRpxRDX0ocyh1KA8wihA6JTeWFA6x0ALls5sIIUEIFKCQE6OsnQO6xzGgScEIs\/zIzwE8DzvCHecc9x4+03iWp3nr1w7NjYYDHDOoZQiCAIAtNaEYTjl8kH+Y4DOOdrtNk\/+ppSi0WgwHA5QykMpD3AIKREqxDqBA9p5lw\/2t1iK57i2+NyRHEIIjpbyODzPwxhDGIbUarUjY\/VaHanUkQqzEtLCkI\/2GfU6nCznqO8JWDyee+aR+r5Pt9vlozs7\/OXNt\/jjH37PzZs3wTmstdPFy8vLvPvuu+R5Pl0vpeTJfE+t0DnH3t4ev\/ntr\/ndG29QiWNKXbB26gybV77E1nvvcPvm+9OEWVGSFQYQBIEPCASWWsU\/fnqzALXWpFmGtpafv\/46J09vsPNwl\/fe3+KlF1\/g69\/6NvvdNjsfvg9AFEVYaemUu9xLdpC6hhuu85VLczjnng4ohCDPM775jev0en1Ori0RRiHddgcpBQuxYqV5mgtnTgJQlJZBotk3Bf2xRuoCvzCzUs8GlFLSnF\/Cbt\/hwYNH\/Ptf7yGkIpCOpHOfhXPrZIUhCv9vV2M3IvQU5+ILMK6wWCmeHRCgGtdIx5p00OHezn2KPOP8xec4sbJMFHiEvk8YTjgXedCqSQba4oQFz6JKfew4YaK1MyOOQj5\/5SqdTocz6y1CkTPq7XL54nnmalUkhnocAZAkCSoTrHpLnKotcGopJlqof5YKBYEvObu+yvd\/\/BO2b33A6XOXWGjNc2HjLGElRuuS\/nAITGgkpURKibEGgZidFhBFUTjgCG+sMZRm8tH3e11Gw8GUS845FpdXqVQqU7A0SUjHY6SUlGWJlBKlPFqt+eNKcxjoANgPAg4YVOoq6bCPcxYlJc5BvV7D94Pp\/H7m+O\/OCCEEgR+gPEEUOFqtZzzShw8fIqUEHM5Btdmi0WggpSRJEgaDIb7vT3edaslu6hN4Er+UJHlBHFqubBy\/NDPF+0m3yLIMYyxCTHT2wBEOKsyyDF2WRI\/dAT7ZLY5VKITgez\/8EeMiZzQa4QUBUgjATUABISWlLqlEIS+\/8AK\/eO01wiCAyTQ83ycMQ8qyfDalUdUYYw1xax4hPeYadcZZhrOTy5SmKVJ6yEqEEZK836YQAVGlMrlEaYq1dlrh4ZjJQ2MMxjr8IGSh2cCOUurCY96PcElOs9HECxTD0QgpBYVXJUkHaK2x1iKEQGs9K\/VsQKdLsAadZ4TOsra2zK0Pt7h1+yMCqVDGYq3FliXOWCQOKXw8pTDGYK09dg8+FXDU79PfazPs9tBIbm9tMRgM2dy8RFCrIQWMOl3S\/pBxmuKUoTQlWV5gjCHP8plg8Anf8PK1E7QurfKfP4\/xy5R6o05Z5OztPiAZpYTVECUdnrRIQIwSlFTAxKAd7jGtnhFwtXmJUIdsbvYQOmM4GHH9+ivUmzWMLpFKUVoo8oILF86jqnOYXveIwx9+PxwzWwxrLWVZPvbFnCRJprIWRRFxHE\/nBkFAng4YJjlBGBJFEVLKiWIdEocpD5\/cwUGSA3InowH37mxN+ees5cq1lwjDiVM453BSojyF7wcT9zcGO8OaZlb4pLYexM72LaKowtLK+rGxYbJPr9MnDCPmmk2MdVQq0bFW81ObqCcFfWl5DSnVkbEDFREiphpn1BvzKKVQj7s7daid\/EwVHh6bABzdzNPiSOdtjHnqilxbjJ3833OAc+B7EmsdQkyaqEqgUPKTjfcg\/geiigyZapzK0gAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/oursong_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022603\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKonkurs muzyczny, w kt\u00f3rym menad\u017cerowie prowadz\u0105cy wybrane przez siebie kraje z ca\u0142ego \u015bwiata co tydzie\u0144 rywalizuj\u0105 o miano najlepszego utworu.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u00221005\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAkCAYAAACaJFpUAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhElEQVRIiZWXW48cRxmGn6rq0\/ScdmfP6+Pasr2RA0bYkIOQIoyAIIE4SMAlEvwJFEWIn8AlcBP+ATdcAOIiikSEsAgRgQSvYsfr9SHrncPOoXu6u7qquBjvsOudxM4ntdSaqvre+qrrfd9vhLXWCSFwziGEIMsyOp0O9XodACHE9InjmE+LdncAJiGqTNZWq1WEEEfmiM+9\/Ir72qLkvlbc1j5KwNW6pVaJkM0ldjsd5poNiixle28fs3yWhw8eIpxFOAcLKzR\/8FPS0hBIyUoccHm+ylolYCnyyYzlUabZywo+Hmu8cT7GaY+2baDCmKzfZt8VMB7iD7psrKxSrYd4YcblhWVu3NlmN8vQKqLIxlSDACUgNxYLxJ7kYr3CfOgRSck+JQ3fQwlBw\/fwAAJPMiwjwjBkZOFG13BqcZ6fvfpV3vnnP3jxi1dZHN+l12mj4gYnHnV4e7tH2wZsNGM25JjyxDIAX2jV2JyLcc4hBcyFinXr2C9KxqXFE0BHS6wz5FoTBxJdgAsjtgcZr37nu\/h5nyRNOHt6nbgIqEtNpARv3R1wai4ifPAR15\/fRAqQwF6mETjW4oCqJ3HAYuiRGYtav\/jcL3vOo7AOz\/MYpynGlKz6OcnuXXof32e9EfKrP73DOdcBAautCmm\/w72B5e6jLiUeV659mZE27I4LPClo+IpQCZQU5MaRWwcCJEIx0gYRVvCaC8zNt1hZWmatEbE7KhHKY5wXbMxXuLk7oH1\/B18ZXl7L8VzJUj2mnyRsJwWPck2oJANt6BeGkbZ0spKxsYyNmeD89W9\/dwhASLyognKWMPApxinOWRpxRDX0ocyh1KA8wihA6JTeWFA6x0ALls5sIIUEIFKCQE6OsnQO6xzGgScEIs\/zIzwE8DzvCHecc9x4+03iWp3nr1w7NjYYDHDOoZQiCAIAtNaEYTjl8kH+Y4DOOdrtNk\/+ppSi0WgwHA5QykMpD3AIKREqxDqBA9p5lw\/2t1iK57i2+NyRHEIIjpbyODzPwxhDGIbUarUjY\/VaHanUkQqzEtLCkI\/2GfU6nCznqO8JWDyee+aR+r5Pt9vlozs7\/OXNt\/jjH37PzZs3wTmstdPFy8vLvPvuu+R5Pl0vpeTJfE+t0DnH3t4ev\/ntr\/ndG29QiWNKXbB26gybV77E1nvvcPvm+9OEWVGSFQYQBIEPCASWWsU\/fnqzALXWpFmGtpafv\/46J09vsPNwl\/fe3+KlF1\/g69\/6NvvdNjsfvg9AFEVYaemUu9xLdpC6hhuu85VLczjnng4ohCDPM775jev0en1Ori0RRiHddgcpBQuxYqV5mgtnTgJQlJZBotk3Bf2xRuoCvzCzUs8GlFLSnF\/Cbt\/hwYNH\/Ptf7yGkIpCOpHOfhXPrZIUhCv9vV2M3IvQU5+ILMK6wWCmeHRCgGtdIx5p00OHezn2KPOP8xec4sbJMFHiEvk8YTjgXedCqSQba4oQFz6JKfew4YaK1MyOOQj5\/5SqdTocz6y1CkTPq7XL54nnmalUkhnocAZAkCSoTrHpLnKotcGopJlqof5YKBYEvObu+yvd\/\/BO2b33A6XOXWGjNc2HjLGElRuuS\/nAITGgkpURKibEGgZidFhBFUTjgCG+sMZRm8tH3e11Gw8GUS845FpdXqVQqU7A0SUjHY6SUlGWJlBKlPFqt+eNKcxjoANgPAg4YVOoq6bCPcxYlJc5BvV7D94Pp\/H7m+O\/OCCEEgR+gPEEUOFqtZzzShw8fIqUEHM5Btdmi0WggpSRJEgaDIb7vT3edaslu6hN4Er+UJHlBHFqubBy\/NDPF+0m3yLIMYyxCTHT2wBEOKsyyDF2WRI\/dAT7ZLY5VKITgez\/8EeMiZzQa4QUBUgjATUABISWlLqlEIS+\/8AK\/eO01wiCAyTQ83ycMQ8qyfDalUdUYYw1xax4hPeYadcZZhrOTy5SmKVJ6yEqEEZK836YQAVGlMrlEaYq1dlrh4ZjJQ2MMxjr8IGSh2cCOUurCY96PcElOs9HECxTD0QgpBYVXJUkHaK2x1iKEQGs9K\/VsQKdLsAadZ4TOsra2zK0Pt7h1+yMCqVDGYq3FliXOWCQOKXw8pTDGYK09dg8+FXDU79PfazPs9tBIbm9tMRgM2dy8RFCrIQWMOl3S\/pBxmuKUoTQlWV5gjCHP8plg8Anf8PK1E7QurfKfP4\/xy5R6o05Z5OztPiAZpYTVECUdnrRIQIwSlFTAxKAd7jGtnhFwtXmJUIdsbvYQOmM4GHH9+ivUmzWMLpFKUVoo8oILF86jqnOYXveIwx9+PxwzWwxrLWVZPvbFnCRJprIWRRFxHE\/nBkFAng4YJjlBGBJFEVLKiWIdEocpD5\/cwUGSA3InowH37mxN+ees5cq1lwjDiVM453BSojyF7wcT9zcGO8OaZlb4pLYexM72LaKowtLK+rGxYbJPr9MnDCPmmk2MdVQq0bFW81ObqCcFfWl5DSnVkbEDFREiphpn1BvzKKVQj7s7daid\/EwVHh6bABzdzNPiSOdtjHnqilxbjJ3833OAc+B7EmsdQkyaqEqgUPKTjfcg\/geiigyZapzK0gAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u00221005\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKonkurs muzyczny, w kt\u00f3rym menad\u017cerowie prowadz\u0105cy wybrane przez siebie kraje z ca\u0142ego \u015bwiata co tydzie\u0144 rywalizuj\u0105 o miano najlepszego utworu.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["eurowizja","facebook","g\u0142osowanie","javascript","konkurs","muzyka","php","piosenka","programowanie","websockets"],"hasMore":false,"image":"https:\/\/avris.it\/image\/oursong_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022301.5\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKonkurs muzyczny, w kt\u00f3rym menad\u017cerowie prowadz\u0105cy wybrane przez siebie kraje z ca\u0142ego \u015bwiata co tydzie\u0144 rywalizuj\u0105 o miano najlepszego utworu.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022301.5\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKonkurs muzyczny, w kt\u00f3rym menad\u017cerowie prowadz\u0105cy wybrane przez siebie kraje z ca\u0142ego \u015bwiata co tydzie\u0144 rywalizuj\u0105 o miano najlepszego utworu.\u003C\/p\u003E","words":24,"readTime":null,"lang":"pl"}}},"blog\/technology\/brand-new-blog":{"key":"blog\/technology\/brand-new-blog","type":"article","published":true,"meta":{"createdAt":"2017-04-30T21:22:09+02:00","publishedAt":"2017-04-30T21:05:00+02:00","group":"redesign","category":"blog","subcategory":"technology","slug":"brand-new-blog"},"content":{"en":{"slug":"brand-new-blog","title":"Brand new blog","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/new-avris_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022250.4347826087\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFD0lEQVRIia2Wz4tdWRHHP1Xn3Pt+dNuvO+m0GY2jOATHzDBmoy5E3Sgogrh14d6\/wIUr3fgfjBtBXLgRN6OIIDKIoMK4GCGgTMCJmR9J6CTTmZ5+\/d6995yqcnFfMll0Bgc8m1N1qjj1rTp1v3UlIoIz1u3btymlsFjssru7OMuFo3feISKYb22xXJ6ws7Pg\/v377O\/v8+DBA5qmQVXp+57JZEI66Zg\/tU8\/DMznc0SEiEBEAEb5Z7\/8VSAgqogqDogk3J1mOkUF0ASipJSJpIgIWRKBsLkLBUISouOBANRKRECAh1PKAEkJq4RV3AyvhbAAN1RApp96LnQ6JU1mpJRxnEDI0zm5acnTGeRMmswgNaTpjEYSOSlIptpAAhRBRGimc6pVdOgRB\/ERTB06hnDCg269xLolpe\/x9Ql1tcLLwEQSudVEO5mRZ9tIkxmGNeHBpG1xTeCG9IaKItMM3Sky3xkhWCEVw1QgTVE3ymqF1YqaM53vUK0Q3QohoUOHu6MB7qC1UiUhzYTkguPkWh1fvsd2bmjaltUwYC6gKyqJlBs8KU1AUwvNdI6dntBOJ1goeWvB1myHWn2s4HrN0o8xK1z5+AVidcxr12\/RVwerDH2PheOrY7wMYAbmuBsaTrYQwhPH7x4jqzWqiUgN666gjRJiaG759le\/RDuZ8cdXr\/GtL36Ol\/7yDybbC2S+YN1sEQyIKLu7mY\/plJyE1eoU6QuXLh4gAsuTJW++fQdD8DzFhop7hWqEGR6Q8s6FH3kYooJ5ECi+adRmOqfZ3uP5z1zm1z\/5AQh892tf5sXf\/ol3B6NPE8pg9N0pw9DRrU+o61PObc2IqLQ5oznhtdJKcOvOIe91A1EGrFSslBGQVbwWkkD2cNAGcxAFs0pKCXKLaSIi+PrnX+D1t+\/wr\/+8xYsvvcxyqGhqiG6NJSMINAIPo20yxbbAjW4oZAlKGejNKO50\/Rpxx6oRCBGCx1gIEKS5+NkgJyQl0AbJCZl9hDTbxsNA4MrlZ7h0YZ\/ejINze\/zmb69iCJoTmltAUDNwx7xyaW9BrRW8kiLACtTK4eFd+m5FVAeCqAPhPtJAKbSayBEOoeCBpA2X1Ep0HSEBqtw7vIfUyt3jJSdPnRLrDgS8aYhhQDSBCF7HJn3r9ilujoYRpRJWEDe8VsKciAJDIawiHkQ4EgJhSDp4NiQlIo3ZelJSnoxfl8jIcAJoi6SM5rw5UzSN\/aYBgcOGZ3AjfHzGsIJbRZ1Nr9gIxHrCIGwgzBCEVgX5819fCUR4RLmim10eUTpsgG2YOZCHLgRAvC\/LRg8CiRif5uFwCh89wkfnx3VARJC+7+Oh8nCuPL4\/vs6y\/b\/lfObUBG7evEnOmel0SkSwWCxo2\/aR\/caNG+zt7VFrRVU5f\/78k676UOuJgI4Ob3Jut+V0DZNJw9Jakiqq0M4OODg4IKWRFh5m+XhF\/xf5QwH6xc9\/zNVn3yU5\/O73d7m4P+M739hnZydx\/pnv8emr36dpGgBevnaXi3sdz31iB4BSCsAj+\/VbJxwe93zlyj4AtVbc\/cy4+iRAR1Wwy3v84e8d33z+C5R7c3740zd4bfccw+KFMXB1+mJsTzOTrPTFqPZ+oIigmpOTMMlKN9gHVucDK3S07Hnlnys+Wc9x\/c271GIcHxauvX7E6Rv\/5umPXsVC6Abj0gJg4N7RwKxN5E2aKSXWgzFX5+k9pesHlPFfS\/XsWvwX97wRJTQmN3gAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/new-avris_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022250.4347826087\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFinally. I got to work and rewrote the code of my sweet blog. Brand new design, new framework, \u003Ca href=\u0022\/projects\/micrus-tiny-yet-powerful-php-framework\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Micrus\u003C\/a\u003E, better support for language versions, a couple of new features in the admin panel, ditching custom comments for the awesomeness of \u003Ca href=\u0022https:\/\/disqus.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Disqus\u003C\/a\u003E, ditching TinyMCE for the beauty and simplicity of Markdown. It was a lot of work, but it was definitely worth it!\u003C\/p\u003E\n\u003Cp\u003EHope you like it! :)\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/new-avris_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022500.86956521739\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFD0lEQVRIia2Wz4tdWRHHP1Xn3Pt+dNuvO+m0GY2jOATHzDBmoy5E3Sgogrh14d6\/wIUr3fgfjBtBXLgRN6OIIDKIoMK4GCGgTMCJmR9J6CTTmZ5+\/d6995yqcnFfMll0Bgc8m1N1qjj1rTp1v3UlIoIz1u3btymlsFjssru7OMuFo3feISKYb22xXJ6ws7Pg\/v377O\/v8+DBA5qmQVXp+57JZEI66Zg\/tU8\/DMznc0SEiEBEAEb5Z7\/8VSAgqogqDogk3J1mOkUF0ASipJSJpIgIWRKBsLkLBUISouOBANRKRECAh1PKAEkJq4RV3AyvhbAAN1RApp96LnQ6JU1mpJRxnEDI0zm5acnTGeRMmswgNaTpjEYSOSlIptpAAhRBRGimc6pVdOgRB\/ERTB06hnDCg269xLolpe\/x9Ql1tcLLwEQSudVEO5mRZ9tIkxmGNeHBpG1xTeCG9IaKItMM3Sky3xkhWCEVw1QgTVE3ymqF1YqaM53vUK0Q3QohoUOHu6MB7qC1UiUhzYTkguPkWh1fvsd2bmjaltUwYC6gKyqJlBs8KU1AUwvNdI6dntBOJ1goeWvB1myHWn2s4HrN0o8xK1z5+AVidcxr12\/RVwerDH2PheOrY7wMYAbmuBsaTrYQwhPH7x4jqzWqiUgN666gjRJiaG759le\/RDuZ8cdXr\/GtL36Ol\/7yDybbC2S+YN1sEQyIKLu7mY\/plJyE1eoU6QuXLh4gAsuTJW++fQdD8DzFhop7hWqEGR6Q8s6FH3kYooJ5ECi+adRmOqfZ3uP5z1zm1z\/5AQh892tf5sXf\/ol3B6NPE8pg9N0pw9DRrU+o61PObc2IqLQ5oznhtdJKcOvOIe91A1EGrFSslBGQVbwWkkD2cNAGcxAFs0pKCXKLaSIi+PrnX+D1t+\/wr\/+8xYsvvcxyqGhqiG6NJSMINAIPo20yxbbAjW4oZAlKGejNKO50\/Rpxx6oRCBGCx1gIEKS5+NkgJyQl0AbJCZl9hDTbxsNA4MrlZ7h0YZ\/ejINze\/zmb69iCJoTmltAUDNwx7xyaW9BrRW8kiLACtTK4eFd+m5FVAeCqAPhPtJAKbSayBEOoeCBpA2X1Ep0HSEBqtw7vIfUyt3jJSdPnRLrDgS8aYhhQDSBCF7HJn3r9ilujoYRpRJWEDe8VsKciAJDIawiHkQ4EgJhSDp4NiQlIo3ZelJSnoxfl8jIcAJoi6SM5rw5UzSN\/aYBgcOGZ3AjfHzGsIJbRZ1Nr9gIxHrCIGwgzBCEVgX5819fCUR4RLmim10eUTpsgG2YOZCHLgRAvC\/LRg8CiRif5uFwCh89wkfnx3VARJC+7+Oh8nCuPL4\/vs6y\/b\/lfObUBG7evEnOmel0SkSwWCxo2\/aR\/caNG+zt7VFrRVU5f\/78k676UOuJgI4Ob3Jut+V0DZNJw9Jakiqq0M4OODg4IKWRFh5m+XhF\/xf5QwH6xc9\/zNVn3yU5\/O73d7m4P+M739hnZydx\/pnv8emr36dpGgBevnaXi3sdz31iB4BSCsAj+\/VbJxwe93zlyj4AtVbc\/cy4+iRAR1Wwy3v84e8d33z+C5R7c3740zd4bfccw+KFMXB1+mJsTzOTrPTFqPZ+oIigmpOTMMlKN9gHVucDK3S07Hnlnys+Wc9x\/c271GIcHxauvX7E6Rv\/5umPXsVC6Abj0gJg4N7RwKxN5E2aKSXWgzFX5+k9pesHlPFfS\/XsWvwX97wRJTQmN3gAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/new-avris_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022500.86956521739\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFinally. I got to work and rewrote the code of my sweet blog. Brand new design, new framework, \u003Ca href=\u0022\/projects\/micrus-tiny-yet-powerful-php-framework\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Micrus\u003C\/a\u003E, better support for language versions, a couple of new features in the admin panel, ditching custom comments for the awesomeness of \u003Ca href=\u0022https:\/\/disqus.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Disqus\u003C\/a\u003E, ditching TinyMCE for the beauty and simplicity of Markdown. It was a lot of work, but it was definitely worth it!\u003C\/p\u003E\n\u003Cp\u003EHope you like it! :)\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["blog","comments","design","disqus","framework","markdown","php","programming","redesign","tinymce","work"],"hasMore":false,"image":"https:\/\/avris.it\/image\/new-avris_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/new-avris_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/new-avris_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022125.21739130435\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFinally. I got to work and rewrote the code of my sweet blog. Brand new design, new framework, \u003Ca href=\u0022\/projects\/micrus-tiny-yet-powerful-php-framework.lite\u0022\u003E Micrus\u003C\/a\u003E, better support for language versions, a couple of new features in the admin panel, ditching custom comments for the awesomeness of \u003Ca href=\u0022https:\/\/disqus.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Disqus\u003C\/a\u003E, ditching TinyMCE for the beauty and simplicity of Markdown. It was a lot of work, but it was definitely worth it!\u003C\/p\u003E\n\u003Cp\u003EHope you like it! :)\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/new-avris_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/new-avris_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022125.21739130435\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFinally. I got to work and rewrote the code of my sweet blog. Brand new design, new framework, \u003Ca href=\u0022\/projects\/micrus-tiny-yet-powerful-php-framework.lite\u0022\u003E Micrus\u003C\/a\u003E, better support for language versions, a couple of new features in the admin panel, ditching custom comments for the awesomeness of \u003Ca href=\u0022https:\/\/disqus.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Disqus\u003C\/a\u003E, ditching TinyMCE for the beauty and simplicity of Markdown. It was a lot of work, but it was definitely worth it!\u003C\/p\u003E\n\u003Cp\u003EHope you like it! :)\u003C\/p\u003E","words":66,"readTime":null,"lang":"en"},"pl":{"slug":"nowiutki-blog","title":"Nowiutki blog","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/new-avris_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022250.4347826087\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFD0lEQVRIia2Wz4tdWRHHP1Xn3Pt+dNuvO+m0GY2jOATHzDBmoy5E3Sgogrh14d6\/wIUr3fgfjBtBXLgRN6OIIDKIoMK4GCGgTMCJmR9J6CTTmZ5+\/d6995yqcnFfMll0Bgc8m1N1qjj1rTp1v3UlIoIz1u3btymlsFjssru7OMuFo3feISKYb22xXJ6ws7Pg\/v377O\/v8+DBA5qmQVXp+57JZEI66Zg\/tU8\/DMznc0SEiEBEAEb5Z7\/8VSAgqogqDogk3J1mOkUF0ASipJSJpIgIWRKBsLkLBUISouOBANRKRECAh1PKAEkJq4RV3AyvhbAAN1RApp96LnQ6JU1mpJRxnEDI0zm5acnTGeRMmswgNaTpjEYSOSlIptpAAhRBRGimc6pVdOgRB\/ERTB06hnDCg269xLolpe\/x9Ql1tcLLwEQSudVEO5mRZ9tIkxmGNeHBpG1xTeCG9IaKItMM3Sky3xkhWCEVw1QgTVE3ymqF1YqaM53vUK0Q3QohoUOHu6MB7qC1UiUhzYTkguPkWh1fvsd2bmjaltUwYC6gKyqJlBs8KU1AUwvNdI6dntBOJ1goeWvB1myHWn2s4HrN0o8xK1z5+AVidcxr12\/RVwerDH2PheOrY7wMYAbmuBsaTrYQwhPH7x4jqzWqiUgN666gjRJiaG759le\/RDuZ8cdXr\/GtL36Ol\/7yDybbC2S+YN1sEQyIKLu7mY\/plJyE1eoU6QuXLh4gAsuTJW++fQdD8DzFhop7hWqEGR6Q8s6FH3kYooJ5ECi+adRmOqfZ3uP5z1zm1z\/5AQh892tf5sXf\/ol3B6NPE8pg9N0pw9DRrU+o61PObc2IqLQ5oznhtdJKcOvOIe91A1EGrFSslBGQVbwWkkD2cNAGcxAFs0pKCXKLaSIi+PrnX+D1t+\/wr\/+8xYsvvcxyqGhqiG6NJSMINAIPo20yxbbAjW4oZAlKGejNKO50\/Rpxx6oRCBGCx1gIEKS5+NkgJyQl0AbJCZl9hDTbxsNA4MrlZ7h0YZ\/ejINze\/zmb69iCJoTmltAUDNwx7xyaW9BrRW8kiLACtTK4eFd+m5FVAeCqAPhPtJAKbSayBEOoeCBpA2X1Ep0HSEBqtw7vIfUyt3jJSdPnRLrDgS8aYhhQDSBCF7HJn3r9ilujoYRpRJWEDe8VsKciAJDIawiHkQ4EgJhSDp4NiQlIo3ZelJSnoxfl8jIcAJoi6SM5rw5UzSN\/aYBgcOGZ3AjfHzGsIJbRZ1Nr9gIxHrCIGwgzBCEVgX5819fCUR4RLmim10eUTpsgG2YOZCHLgRAvC\/LRg8CiRif5uFwCh89wkfnx3VARJC+7+Oh8nCuPL4\/vs6y\/b\/lfObUBG7evEnOmel0SkSwWCxo2\/aR\/caNG+zt7VFrRVU5f\/78k676UOuJgI4Ob3Jut+V0DZNJw9Jakiqq0M4OODg4IKWRFh5m+XhF\/xf5QwH6xc9\/zNVn3yU5\/O73d7m4P+M739hnZydx\/pnv8emr36dpGgBevnaXi3sdz31iB4BSCsAj+\/VbJxwe93zlyj4AtVbc\/cy4+iRAR1Wwy3v84e8d33z+C5R7c3740zd4bfccw+KFMXB1+mJsTzOTrPTFqPZ+oIigmpOTMMlKN9gHVucDK3S07Hnlnys+Wc9x\/c271GIcHxauvX7E6Rv\/5umPXsVC6Abj0gJg4N7RwKxN5E2aKSXWgzFX5+k9pesHlPFfS\/XsWvwX97wRJTQmN3gAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/new-avris_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022250.4347826087\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWreszcie. Wzi\u0105\u0142em si\u0119 do roboty i przepisa\u0142em od zera kod mojego blogaska. Zupe\u0142nie nowy design, nowy framework, \u003Ca href=\u0022\/projects\/micrus-tiny-yet-powerful-php-framework\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Micrus\u003C\/a\u003E, lepsze wsparcie dla wersji j\u0119zykowych, par\u0119 nowych ficzer\u00f3w w panelu administracyjnym, rzucenie w\u0142asnego systemu komentarzy na rzecz zajebisto\u015bci \u003Ca href=\u0022https:\/\/disqus.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Disqusa\u003C\/a\u003E, rzucenie TinyMCE dla pi\u0119kna i prostoty Markdownu. Zaj\u0119\u0142o to sporo pracy, ale zdecydowanie by\u0142o warto!\u003C\/p\u003E\n\u003Cp\u003EMam nadziej\u0119, \u017ce si\u0119 spodoba! :)\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/new-avris_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022500.86956521739\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFD0lEQVRIia2Wz4tdWRHHP1Xn3Pt+dNuvO+m0GY2jOATHzDBmoy5E3Sgogrh14d6\/wIUr3fgfjBtBXLgRN6OIIDKIoMK4GCGgTMCJmR9J6CTTmZ5+\/d6995yqcnFfMll0Bgc8m1N1qjj1rTp1v3UlIoIz1u3btymlsFjssru7OMuFo3feISKYb22xXJ6ws7Pg\/v377O\/v8+DBA5qmQVXp+57JZEI66Zg\/tU8\/DMznc0SEiEBEAEb5Z7\/8VSAgqogqDogk3J1mOkUF0ASipJSJpIgIWRKBsLkLBUISouOBANRKRECAh1PKAEkJq4RV3AyvhbAAN1RApp96LnQ6JU1mpJRxnEDI0zm5acnTGeRMmswgNaTpjEYSOSlIptpAAhRBRGimc6pVdOgRB\/ERTB06hnDCg269xLolpe\/x9Ql1tcLLwEQSudVEO5mRZ9tIkxmGNeHBpG1xTeCG9IaKItMM3Sky3xkhWCEVw1QgTVE3ymqF1YqaM53vUK0Q3QohoUOHu6MB7qC1UiUhzYTkguPkWh1fvsd2bmjaltUwYC6gKyqJlBs8KU1AUwvNdI6dntBOJ1goeWvB1myHWn2s4HrN0o8xK1z5+AVidcxr12\/RVwerDH2PheOrY7wMYAbmuBsaTrYQwhPH7x4jqzWqiUgN666gjRJiaG759le\/RDuZ8cdXr\/GtL36Ol\/7yDybbC2S+YN1sEQyIKLu7mY\/plJyE1eoU6QuXLh4gAsuTJW++fQdD8DzFhop7hWqEGR6Q8s6FH3kYooJ5ECi+adRmOqfZ3uP5z1zm1z\/5AQh892tf5sXf\/ol3B6NPE8pg9N0pw9DRrU+o61PObc2IqLQ5oznhtdJKcOvOIe91A1EGrFSslBGQVbwWkkD2cNAGcxAFs0pKCXKLaSIi+PrnX+D1t+\/wr\/+8xYsvvcxyqGhqiG6NJSMINAIPo20yxbbAjW4oZAlKGejNKO50\/Rpxx6oRCBGCx1gIEKS5+NkgJyQl0AbJCZl9hDTbxsNA4MrlZ7h0YZ\/ejINze\/zmb69iCJoTmltAUDNwx7xyaW9BrRW8kiLACtTK4eFd+m5FVAeCqAPhPtJAKbSayBEOoeCBpA2X1Ep0HSEBqtw7vIfUyt3jJSdPnRLrDgS8aYhhQDSBCF7HJn3r9ilujoYRpRJWEDe8VsKciAJDIawiHkQ4EgJhSDp4NiQlIo3ZelJSnoxfl8jIcAJoi6SM5rw5UzSN\/aYBgcOGZ3AjfHzGsIJbRZ1Nr9gIxHrCIGwgzBCEVgX5819fCUR4RLmim10eUTpsgG2YOZCHLgRAvC\/LRg8CiRif5uFwCh89wkfnx3VARJC+7+Oh8nCuPL4\/vs6y\/b\/lfObUBG7evEnOmel0SkSwWCxo2\/aR\/caNG+zt7VFrRVU5f\/78k676UOuJgI4Ob3Jut+V0DZNJw9Jakiqq0M4OODg4IKWRFh5m+XhF\/xf5QwH6xc9\/zNVn3yU5\/O73d7m4P+M739hnZydx\/pnv8emr36dpGgBevnaXi3sdz31iB4BSCsAj+\/VbJxwe93zlyj4AtVbc\/cy4+iRAR1Wwy3v84e8d33z+C5R7c3740zd4bfccw+KFMXB1+mJsTzOTrPTFqPZ+oIigmpOTMMlKN9gHVucDK3S07Hnlnys+Wc9x\/c271GIcHxauvX7E6Rv\/5umPXsVC6Abj0gJg4N7RwKxN5E2aKSXWgzFX5+k9pesHlPFfS\/XsWvwX97wRJTQmN3gAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/new-avris_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022500.86956521739\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWreszcie. Wzi\u0105\u0142em si\u0119 do roboty i przepisa\u0142em od zera kod mojego blogaska. Zupe\u0142nie nowy design, nowy framework, \u003Ca href=\u0022\/projects\/micrus-tiny-yet-powerful-php-framework\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Micrus\u003C\/a\u003E, lepsze wsparcie dla wersji j\u0119zykowych, par\u0119 nowych ficzer\u00f3w w panelu administracyjnym, rzucenie w\u0142asnego systemu komentarzy na rzecz zajebisto\u015bci \u003Ca href=\u0022https:\/\/disqus.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Disqusa\u003C\/a\u003E, rzucenie TinyMCE dla pi\u0119kna i prostoty Markdownu. Zaj\u0119\u0142o to sporo pracy, ale zdecydowanie by\u0142o warto!\u003C\/p\u003E\n\u003Cp\u003EMam nadziej\u0119, \u017ce si\u0119 spodoba! :)\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["design","framework","komentarz","markdown","php","praca","programowanie","redesign","tinymce"],"hasMore":false,"image":"https:\/\/avris.it\/image\/new-avris_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/new-avris_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/new-avris_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022125.21739130435\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWreszcie. Wzi\u0105\u0142em si\u0119 do roboty i przepisa\u0142em od zera kod mojego blogaska. Zupe\u0142nie nowy design, nowy framework, \u003Ca href=\u0022\/projects\/micrus-tiny-yet-powerful-php-framework.lite\u0022\u003E Micrus\u003C\/a\u003E, lepsze wsparcie dla wersji j\u0119zykowych, par\u0119 nowych ficzer\u00f3w w panelu administracyjnym, rzucenie w\u0142asnego systemu komentarzy na rzecz zajebisto\u015bci \u003Ca href=\u0022https:\/\/disqus.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Disqusa\u003C\/a\u003E, rzucenie TinyMCE dla pi\u0119kna i prostoty Markdownu. Zaj\u0119\u0142o to sporo pracy, ale zdecydowanie by\u0142o warto!\u003C\/p\u003E\n\u003Cp\u003EMam nadziej\u0119, \u017ce si\u0119 spodoba! :)\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/new-avris_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/new-avris_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022125.21739130435\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWreszcie. Wzi\u0105\u0142em si\u0119 do roboty i przepisa\u0142em od zera kod mojego blogaska. Zupe\u0142nie nowy design, nowy framework, \u003Ca href=\u0022\/projects\/micrus-tiny-yet-powerful-php-framework.lite\u0022\u003E Micrus\u003C\/a\u003E, lepsze wsparcie dla wersji j\u0119zykowych, par\u0119 nowych ficzer\u00f3w w panelu administracyjnym, rzucenie w\u0142asnego systemu komentarzy na rzecz zajebisto\u015bci \u003Ca href=\u0022https:\/\/disqus.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Disqusa\u003C\/a\u003E, rzucenie TinyMCE dla pi\u0119kna i prostoty Markdownu. Zaj\u0119\u0142o to sporo pracy, ale zdecydowanie by\u0142o warto!\u003C\/p\u003E\n\u003Cp\u003EMam nadziej\u0119, \u017ce si\u0119 spodoba! :)\u003C\/p\u003E","words":67,"readTime":null,"lang":"pl"}}},"projects\/micrus-tiny-yet-powerful-php-framework":{"key":"projects\/micrus-tiny-yet-powerful-php-framework","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:38+02:00","publishedAt":"2017-03-11T12:00:00+01:00","group":"micrus","links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/micrus.avris.it","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Micrus","displayUrl":null}],"category":"projects","subcategory":null,"slug":"micrus-tiny-yet-powerful-php-framework"},"content":{"en":{"slug":"micrus-tiny-yet-powerful-php-framework","title":"Micrus \u2022 Tiny, yet powerful, PHP framework","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/micrus_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022267.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGCUlEQVRIiU2Wy45dVxGGv6q19u2cvuC2u9NJhIkcCRSQAhKXF2DChAED3odX4Rl4A2CAxEWKlBBQiBOTqON0226f0+eyL6uqGOxj45L2YA\/W0r\/++uv\/S4DgUKKKdDXy1jH66BQi8PVA7Lakmx5dQULIIgy+R0RINJRfnOGdQwpw8PUAvRBjgSggExQHC\/S\/Ai5EBCICQEQQ4UQE+TUYAV0oehLYuMKvB\/SsI192lG9BXwgqUIkyeSEIQIhHS+qfLyk3e8KE6A3JDb4OxBNIS+wK4T2yBG0DGQJBEFE8HPeCWQBvAIpWMAIfHGol1oXYbLD6jvxOIl9m2h00wKqPw8tAukS+l4khE0XwBJ4SqYEoQuwnZKEQCT3N6EVG\/3gLIYDg4QdCBNAZkHSJyEAWIoNk5kvqhAC2Ekwm2p+1NI8z9s2AiOAXNeUE8mhIoyCQTjJ6lMCdGA0fBUkJ0QqpE\/J2xv5zBF+v8XDiAOhVZWQGQpORNkGtSJeQCkggR3mWmSurXWH\/CGTI+LogHx4RJbDbCW0zcpQAATPAASWiQTSBClILooL+6pTp93t0mnAgwl5rSaTOwf0WuoS0h29ZoccZaSCGQrihywQl8MFInRKPd\/DeKVIV6veWSFeRjjIkxfsRLEBnXNoK0iQkKZIzoAz\/2FL+dEO53mOr4bWoRe8tg+8ukEVGjzJ6kmZmMkgF2iraKbYx8CAmRxqhejtDmQgXdFEjbYO2EIMR4WiV53tUkLZC64RUig\/gm6C8HPHNRPQT9mTD9NmW8q87siwFvWzQ4wrtBO0CaQWpBEnz+Ekj5IsGUKarEXtpMMG7lxdUtzVX4wvMChDE3tB7NZIFyRldNogKYeA7JyaIcX4cEfgeLHXI+xX6dCTrsCXdTsjJEelsSXW+RLqM5ABxKDOV+IRo0H2wpP\/3yPjFlt+e\/5o7u+N29xy6gr5sqaj5g\/0Fe5CJKaNFMRuJsRBjzMD6iegN3zs+ODEEsVckZUSSRKqEtBDkoZJ\/sqT6wX2ah2dIlSAc0QB1iCAmQxcdu7+vOF59h4ePLlmvv+aoKzTpmOd75enxS8gxj73NbQsH74OwwDcTtjJsY\/jGsWeF2Bn62S0ChIigqmgSqnPQH2fSh6c033+HfHbvMLazBs6\/rGhTZlFqHq0u+d75gmfrFR\/ffEyjJ2w9UeiRSln5jqsHqxlE7\/hg2KrgeyN284D42rHribgbSFc78iv7BnALpmvl6K8JuV2zeznQfNBTvXUfbWtEMtfvBnko2Ljh0y8+5zcnP+XkvGJVNryonOtPrqgeNkRArit8PLDSF3w7EQNgc6L4OrAXE7Ebif1IhJPlVW4c3LLLFctSM3xaKN9swb9Fcqa6uEDqCrLgyxZNHT988oCPnnyF3I7Y04p7R8rZw\/f58vwlviuUYvid4bsCATEK4YFvA3tRsNVErAdivYfdNMtDZG6ZKFQ5s6xq8GDdj6BC\/Q7wy2OaH13OTFU1uqiBTJQRbQLvJ\/b\/XIGPhENYEDuIaRYtDt77bBsWxN7xreHPB\/zZFu4GohhqQRKR34mAKqQsFJz9WDCf80o3gtyO+JkhtaANs9tFgARSgy4r0ukCSQU08P0IGLE3oi\/4\/jBVdxN2M+I3A347zqz0ZbaB4oQdwlUlkWXWkIcRQK6F0KAUJ74S9M9rpM1IVlIYkgtp2RFlTn1tanRZ4\/2EZCEGA43ZMmJO8nBAAypgcMJmEPghaYJZ1HJI7lIABNFAMugicAe2wOfOeLFClw3aZGjBtk5aVERxCJujsU5om7E7A7dDDgIWiMwtwwKKHXakA9uHrSxHBCVsPgSoKqD4GPOO1AUsIHqIj0aG+2u0bcjnC0TAh5gzJhRM0LrG24K2gg2BJMF9dmjv47VTR5lBiR+MlxlUnn\/eBHNg2BUZYhZiciIFbKH8bcN0voScSYsKaUCbBFKwu4Kt9kiroDrHR5pZ8LtC7IIYHHYGQyEmP7D05vrxRv0fXCCiRAiYIAHhjlsQV4Xx8XaeNFESgk0FyQaSCRfsZgRRIBHms\/gbiBHoD9oZHSab23domTj8DzmtyTndp0MuAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/micrus_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022267.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EHow big does a framework need to be to provide you with a quick, easy and comfortable way of creating neatly structured MVC websites? That can easily be extended and configured?\u003C\/p\u003E\n\u003Cp\u003EWell, not big at all. Just try Micrus! Its goal is to keep it as simple as possible, while offering all the most important features, as listed here:\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/micrus_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022535\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGCUlEQVRIiU2Wy45dVxGGv6q19u2cvuC2u9NJhIkcCRSQAhKXF2DChAED3odX4Rl4A2CAxEWKlBBQiBOTqON0226f0+eyL6uqGOxj45L2YA\/W0r\/++uv\/S4DgUKKKdDXy1jH66BQi8PVA7Lakmx5dQULIIgy+R0RINJRfnOGdQwpw8PUAvRBjgSggExQHC\/S\/Ai5EBCICQEQQ4UQE+TUYAV0oehLYuMKvB\/SsI192lG9BXwgqUIkyeSEIQIhHS+qfLyk3e8KE6A3JDb4OxBNIS+wK4T2yBG0DGQJBEFE8HPeCWQBvAIpWMAIfHGol1oXYbLD6jvxOIl9m2h00wKqPw8tAukS+l4khE0XwBJ4SqYEoQuwnZKEQCT3N6EVG\/3gLIYDg4QdCBNAZkHSJyEAWIoNk5kvqhAC2Ekwm2p+1NI8z9s2AiOAXNeUE8mhIoyCQTjJ6lMCdGA0fBUkJ0QqpE\/J2xv5zBF+v8XDiAOhVZWQGQpORNkGtSJeQCkggR3mWmSurXWH\/CGTI+LogHx4RJbDbCW0zcpQAATPAASWiQTSBClILooL+6pTp93t0mnAgwl5rSaTOwf0WuoS0h29ZoccZaSCGQrihywQl8MFInRKPd\/DeKVIV6veWSFeRjjIkxfsRLEBnXNoK0iQkKZIzoAz\/2FL+dEO53mOr4bWoRe8tg+8ukEVGjzJ6kmZmMkgF2iraKbYx8CAmRxqhejtDmQgXdFEjbYO2EIMR4WiV53tUkLZC64RUig\/gm6C8HPHNRPQT9mTD9NmW8q87siwFvWzQ4wrtBO0CaQWpBEnz+Ekj5IsGUKarEXtpMMG7lxdUtzVX4wvMChDE3tB7NZIFyRldNogKYeA7JyaIcX4cEfgeLHXI+xX6dCTrsCXdTsjJEelsSXW+RLqM5ABxKDOV+IRo0H2wpP\/3yPjFlt+e\/5o7u+N29xy6gr5sqaj5g\/0Fe5CJKaNFMRuJsRBjzMD6iegN3zs+ODEEsVckZUSSRKqEtBDkoZJ\/sqT6wX2ah2dIlSAc0QB1iCAmQxcdu7+vOF59h4ePLlmvv+aoKzTpmOd75enxS8gxj73NbQsH74OwwDcTtjJsY\/jGsWeF2Bn62S0ChIigqmgSqnPQH2fSh6c033+HfHbvMLazBs6\/rGhTZlFqHq0u+d75gmfrFR\/ffEyjJ2w9UeiRSln5jqsHqxlE7\/hg2KrgeyN284D42rHribgbSFc78iv7BnALpmvl6K8JuV2zeznQfNBTvXUfbWtEMtfvBnko2Ljh0y8+5zcnP+XkvGJVNryonOtPrqgeNkRArit8PLDSF3w7EQNgc6L4OrAXE7Ebif1IhJPlVW4c3LLLFctSM3xaKN9swb9Fcqa6uEDqCrLgyxZNHT988oCPnnyF3I7Y04p7R8rZw\/f58vwlviuUYvid4bsCATEK4YFvA3tRsNVErAdivYfdNMtDZG6ZKFQ5s6xq8GDdj6BC\/Q7wy2OaH13OTFU1uqiBTJQRbQLvJ\/b\/XIGPhENYEDuIaRYtDt77bBsWxN7xreHPB\/zZFu4GohhqQRKR34mAKqQsFJz9WDCf80o3gtyO+JkhtaANs9tFgARSgy4r0ukCSQU08P0IGLE3oi\/4\/jBVdxN2M+I3A347zqz0ZbaB4oQdwlUlkWXWkIcRQK6F0KAUJ74S9M9rpM1IVlIYkgtp2RFlTn1tanRZ4\/2EZCEGA43ZMmJO8nBAAypgcMJmEPghaYJZ1HJI7lIABNFAMugicAe2wOfOeLFClw3aZGjBtk5aVERxCJujsU5om7E7A7dDDgIWiMwtwwKKHXakA9uHrSxHBCVsPgSoKqD4GPOO1AUsIHqIj0aG+2u0bcjnC0TAh5gzJhRM0LrG24K2gg2BJMF9dmjv47VTR5lBiR+MlxlUnn\/eBHNg2BUZYhZiciIFbKH8bcN0voScSYsKaUCbBFKwu4Kt9kiroDrHR5pZ8LtC7IIYHHYGQyEmP7D05vrxRv0fXCCiRAiYIAHhjlsQV4Xx8XaeNFESgk0FyQaSCRfsZgRRIBHms\/gbiBHoD9oZHSab23domTj8DzmtyTndp0MuAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/micrus_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022535\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EHow big does a framework need to be to provide you with a quick, easy and comfortable way of creating neatly structured MVC websites? That can easily be extended and configured?\u003C\/p\u003E\n\u003Cp\u003EWell, not big at all. Just try Micrus! Its goal is to keep it as simple as possible, while offering all the most important features, as listed here:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EObject oriented\u003C\/li\u003E\n\u003Cli\u003EVery clear MVC structure\u003C\/li\u003E\n\u003Cli\u003EDependency Injection Container\u003C\/li\u003E\n\u003Cli\u003EEvent dispatching\u003C\/li\u003E\n\u003Cli\u003EORM agnostic, support for Doctrine and RedBean\u003C\/li\u003E\n\u003Cli\u003EREST-ful routing\u003C\/li\u003E\n\u003Cli\u003ECRUD generator\u003C\/li\u003E\n\u003Cli\u003ETemplate engine agnostic, support for Twig and plain PHP\u003C\/li\u003E\n\u003Cli\u003EAuthentication and authorization\u003C\/li\u003E\n\u003Cli\u003EEasy configuration with YAML\u003C\/li\u003E\n\u003Cli\u003EConsole tasks using Symfony Console\u003C\/li\u003E\n\u003Cli\u003EForms\u003C\/li\u003E\n\u003Cli\u003ELocalization\u003C\/li\u003E\n\u003Cli\u003ELogging with Monolog (PSR-3 compliant)\u003C\/li\u003E\n\u003Cli\u003ECaching (PSR-6 compliant)\u003C\/li\u003E\n\u003Cli\u003EFlash messages\u003C\/li\u003E\n\u003C\/ul\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["extendable","framework","full-stack","php","plugins","programming"],"hasMore":true,"image":"https:\/\/avris.it\/image\/micrus_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/micrus_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/micrus_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022133.75\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EHow big does a framework need to be to provide you with a quick, easy and comfortable way of creating neatly structured MVC websites? That can easily be extended and configured?\u003C\/p\u003E\n\u003Cp\u003EWell, not big at all. Just try Micrus! Its goal is to keep it as simple as possible, while offering all the most important features, as listed here:\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/micrus_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/micrus_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022133.75\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EHow big does a framework need to be to provide you with a quick, easy and comfortable way of creating neatly structured MVC websites? That can easily be extended and configured?\u003C\/p\u003E\n\u003Cp\u003EWell, not big at all. Just try Micrus! Its goal is to keep it as simple as possible, while offering all the most important features, as listed here:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EObject oriented\u003C\/li\u003E\n\u003Cli\u003EVery clear MVC structure\u003C\/li\u003E\n\u003Cli\u003EDependency Injection Container\u003C\/li\u003E\n\u003Cli\u003EEvent dispatching\u003C\/li\u003E\n\u003Cli\u003EORM agnostic, support for Doctrine and RedBean\u003C\/li\u003E\n\u003Cli\u003EREST-ful routing\u003C\/li\u003E\n\u003Cli\u003ECRUD generator\u003C\/li\u003E\n\u003Cli\u003ETemplate engine agnostic, support for Twig and plain PHP\u003C\/li\u003E\n\u003Cli\u003EAuthentication and authorization\u003C\/li\u003E\n\u003Cli\u003EEasy configuration with YAML\u003C\/li\u003E\n\u003Cli\u003EConsole tasks using Symfony Console\u003C\/li\u003E\n\u003Cli\u003EForms\u003C\/li\u003E\n\u003Cli\u003ELocalization\u003C\/li\u003E\n\u003Cli\u003ELogging with Monolog (PSR-3 compliant)\u003C\/li\u003E\n\u003Cli\u003ECaching (PSR-6 compliant)\u003C\/li\u003E\n\u003Cli\u003EFlash messages\u003C\/li\u003E\n\u003C\/ul\u003E","words":114,"readTime":null,"lang":"en"},"pl":{"slug":"micrus-drobny-lecz-skuteczny-framework-dla-php","title":"Micrus \u2022 Drobny, lecz skuteczny, framework dla PHP","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/micrus_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022267.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGCUlEQVRIiU2Wy45dVxGGv6q19u2cvuC2u9NJhIkcCRSQAhKXF2DChAED3odX4Rl4A2CAxEWKlBBQiBOTqON0226f0+eyL6uqGOxj45L2YA\/W0r\/++uv\/S4DgUKKKdDXy1jH66BQi8PVA7Lakmx5dQULIIgy+R0RINJRfnOGdQwpw8PUAvRBjgSggExQHC\/S\/Ai5EBCICQEQQ4UQE+TUYAV0oehLYuMKvB\/SsI192lG9BXwgqUIkyeSEIQIhHS+qfLyk3e8KE6A3JDb4OxBNIS+wK4T2yBG0DGQJBEFE8HPeCWQBvAIpWMAIfHGol1oXYbLD6jvxOIl9m2h00wKqPw8tAukS+l4khE0XwBJ4SqYEoQuwnZKEQCT3N6EVG\/3gLIYDg4QdCBNAZkHSJyEAWIoNk5kvqhAC2Ekwm2p+1NI8z9s2AiOAXNeUE8mhIoyCQTjJ6lMCdGA0fBUkJ0QqpE\/J2xv5zBF+v8XDiAOhVZWQGQpORNkGtSJeQCkggR3mWmSurXWH\/CGTI+LogHx4RJbDbCW0zcpQAATPAASWiQTSBClILooL+6pTp93t0mnAgwl5rSaTOwf0WuoS0h29ZoccZaSCGQrihywQl8MFInRKPd\/DeKVIV6veWSFeRjjIkxfsRLEBnXNoK0iQkKZIzoAz\/2FL+dEO53mOr4bWoRe8tg+8ukEVGjzJ6kmZmMkgF2iraKbYx8CAmRxqhejtDmQgXdFEjbYO2EIMR4WiV53tUkLZC64RUig\/gm6C8HPHNRPQT9mTD9NmW8q87siwFvWzQ4wrtBO0CaQWpBEnz+Ekj5IsGUKarEXtpMMG7lxdUtzVX4wvMChDE3tB7NZIFyRldNogKYeA7JyaIcX4cEfgeLHXI+xX6dCTrsCXdTsjJEelsSXW+RLqM5ABxKDOV+IRo0H2wpP\/3yPjFlt+e\/5o7u+N29xy6gr5sqaj5g\/0Fe5CJKaNFMRuJsRBjzMD6iegN3zs+ODEEsVckZUSSRKqEtBDkoZJ\/sqT6wX2ah2dIlSAc0QB1iCAmQxcdu7+vOF59h4ePLlmvv+aoKzTpmOd75enxS8gxj73NbQsH74OwwDcTtjJsY\/jGsWeF2Bn62S0ChIigqmgSqnPQH2fSh6c033+HfHbvMLazBs6\/rGhTZlFqHq0u+d75gmfrFR\/ffEyjJ2w9UeiRSln5jqsHqxlE7\/hg2KrgeyN284D42rHribgbSFc78iv7BnALpmvl6K8JuV2zeznQfNBTvXUfbWtEMtfvBnko2Ljh0y8+5zcnP+XkvGJVNryonOtPrqgeNkRArit8PLDSF3w7EQNgc6L4OrAXE7Ebif1IhJPlVW4c3LLLFctSM3xaKN9swb9Fcqa6uEDqCrLgyxZNHT988oCPnnyF3I7Y04p7R8rZw\/f58vwlviuUYvid4bsCATEK4YFvA3tRsNVErAdivYfdNMtDZG6ZKFQ5s6xq8GDdj6BC\/Q7wy2OaH13OTFU1uqiBTJQRbQLvJ\/b\/XIGPhENYEDuIaRYtDt77bBsWxN7xreHPB\/zZFu4GohhqQRKR34mAKqQsFJz9WDCf80o3gtyO+JkhtaANs9tFgARSgy4r0ukCSQU08P0IGLE3oi\/4\/jBVdxN2M+I3A347zqz0ZbaB4oQdwlUlkWXWkIcRQK6F0KAUJ74S9M9rpM1IVlIYkgtp2RFlTn1tanRZ4\/2EZCEGA43ZMmJO8nBAAypgcMJmEPghaYJZ1HJI7lIABNFAMugicAe2wOfOeLFClw3aZGjBtk5aVERxCJujsU5om7E7A7dDDgIWiMwtwwKKHXakA9uHrSxHBCVsPgSoKqD4GPOO1AUsIHqIj0aG+2u0bcjnC0TAh5gzJhRM0LrG24K2gg2BJMF9dmjv47VTR5lBiR+MlxlUnn\/eBHNg2BUZYhZiciIFbKH8bcN0voScSYsKaUCbBFKwu4Kt9kiroDrHR5pZ8LtC7IIYHHYGQyEmP7D05vrxRv0fXCCiRAiYIAHhjlsQV4Xx8XaeNFESgk0FyQaSCRfsZgRRIBHms\/gbiBHoD9oZHSab23domTj8DzmtyTndp0MuAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/micrus_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022267.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EJak du\u017cy musi by\u0107 framework, aby umo\u017cliwia\u0142 szybkie, \u0142atwe i wygodne tworzenie \u0142adnie uporz\u0105dkowanych stron MVC? Aby by\u0142 \u0142atwo rozszerzalny i konfigurowalny?\u003C\/p\u003E\n\u003Cp\u003ENo w\u0142a\u015bnie wcale nie tak du\u017cy. Wypr\u00f3buj Micrusa!  Jego celem jest bycie tak ma\u0142ym, jak to tylko mo\u017cliwe, lecz oferowa\u0107 wszytkie najwa\u017cniejsze funkcjonalno\u015bci:\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/micrus_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022535\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGCUlEQVRIiU2Wy45dVxGGv6q19u2cvuC2u9NJhIkcCRSQAhKXF2DChAED3odX4Rl4A2CAxEWKlBBQiBOTqON0226f0+eyL6uqGOxj45L2YA\/W0r\/++uv\/S4DgUKKKdDXy1jH66BQi8PVA7Lakmx5dQULIIgy+R0RINJRfnOGdQwpw8PUAvRBjgSggExQHC\/S\/Ai5EBCICQEQQ4UQE+TUYAV0oehLYuMKvB\/SsI192lG9BXwgqUIkyeSEIQIhHS+qfLyk3e8KE6A3JDb4OxBNIS+wK4T2yBG0DGQJBEFE8HPeCWQBvAIpWMAIfHGol1oXYbLD6jvxOIl9m2h00wKqPw8tAukS+l4khE0XwBJ4SqYEoQuwnZKEQCT3N6EVG\/3gLIYDg4QdCBNAZkHSJyEAWIoNk5kvqhAC2Ekwm2p+1NI8z9s2AiOAXNeUE8mhIoyCQTjJ6lMCdGA0fBUkJ0QqpE\/J2xv5zBF+v8XDiAOhVZWQGQpORNkGtSJeQCkggR3mWmSurXWH\/CGTI+LogHx4RJbDbCW0zcpQAATPAASWiQTSBClILooL+6pTp93t0mnAgwl5rSaTOwf0WuoS0h29ZoccZaSCGQrihywQl8MFInRKPd\/DeKVIV6veWSFeRjjIkxfsRLEBnXNoK0iQkKZIzoAz\/2FL+dEO53mOr4bWoRe8tg+8ukEVGjzJ6kmZmMkgF2iraKbYx8CAmRxqhejtDmQgXdFEjbYO2EIMR4WiV53tUkLZC64RUig\/gm6C8HPHNRPQT9mTD9NmW8q87siwFvWzQ4wrtBO0CaQWpBEnz+Ekj5IsGUKarEXtpMMG7lxdUtzVX4wvMChDE3tB7NZIFyRldNogKYeA7JyaIcX4cEfgeLHXI+xX6dCTrsCXdTsjJEelsSXW+RLqM5ABxKDOV+IRo0H2wpP\/3yPjFlt+e\/5o7u+N29xy6gr5sqaj5g\/0Fe5CJKaNFMRuJsRBjzMD6iegN3zs+ODEEsVckZUSSRKqEtBDkoZJ\/sqT6wX2ah2dIlSAc0QB1iCAmQxcdu7+vOF59h4ePLlmvv+aoKzTpmOd75enxS8gxj73NbQsH74OwwDcTtjJsY\/jGsWeF2Bn62S0ChIigqmgSqnPQH2fSh6c033+HfHbvMLazBs6\/rGhTZlFqHq0u+d75gmfrFR\/ffEyjJ2w9UeiRSln5jqsHqxlE7\/hg2KrgeyN284D42rHribgbSFc78iv7BnALpmvl6K8JuV2zeznQfNBTvXUfbWtEMtfvBnko2Ljh0y8+5zcnP+XkvGJVNryonOtPrqgeNkRArit8PLDSF3w7EQNgc6L4OrAXE7Ebif1IhJPlVW4c3LLLFctSM3xaKN9swb9Fcqa6uEDqCrLgyxZNHT988oCPnnyF3I7Y04p7R8rZw\/f58vwlviuUYvid4bsCATEK4YFvA3tRsNVErAdivYfdNMtDZG6ZKFQ5s6xq8GDdj6BC\/Q7wy2OaH13OTFU1uqiBTJQRbQLvJ\/b\/XIGPhENYEDuIaRYtDt77bBsWxN7xreHPB\/zZFu4GohhqQRKR34mAKqQsFJz9WDCf80o3gtyO+JkhtaANs9tFgARSgy4r0ukCSQU08P0IGLE3oi\/4\/jBVdxN2M+I3A347zqz0ZbaB4oQdwlUlkWXWkIcRQK6F0KAUJ74S9M9rpM1IVlIYkgtp2RFlTn1tanRZ4\/2EZCEGA43ZMmJO8nBAAypgcMJmEPghaYJZ1HJI7lIABNFAMugicAe2wOfOeLFClw3aZGjBtk5aVERxCJujsU5om7E7A7dDDgIWiMwtwwKKHXakA9uHrSxHBCVsPgSoKqD4GPOO1AUsIHqIj0aG+2u0bcjnC0TAh5gzJhRM0LrG24K2gg2BJMF9dmjv47VTR5lBiR+MlxlUnn\/eBHNg2BUZYhZiciIFbKH8bcN0voScSYsKaUCbBFKwu4Kt9kiroDrHR5pZ8LtC7IIYHHYGQyEmP7D05vrxRv0fXCCiRAiYIAHhjlsQV4Xx8XaeNFESgk0FyQaSCRfsZgRRIBHms\/gbiBHoD9oZHSab23domTj8DzmtyTndp0MuAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/micrus_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022535\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EJak du\u017cy musi by\u0107 framework, aby umo\u017cliwia\u0142 szybkie, \u0142atwe i wygodne tworzenie \u0142adnie uporz\u0105dkowanych stron MVC? Aby by\u0142 \u0142atwo rozszerzalny i konfigurowalny?\u003C\/p\u003E\n\u003Cp\u003ENo w\u0142a\u015bnie wcale nie tak du\u017cy. Wypr\u00f3buj Micrusa!  Jego celem jest bycie tak ma\u0142ym, jak to tylko mo\u017cliwe, lecz oferowa\u0107 wszytkie najwa\u017cniejsze funkcjonalno\u015bci:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EZorientowany obiektowo\u003C\/li\u003E\n\u003Cli\u003EPrzejrzysta struktura MVC\u003C\/li\u003E\n\u003Cli\u003EKontener DI\u003C\/li\u003E\n\u003Cli\u003EEvent dispatching\u003C\/li\u003E\n\u003Cli\u003EAgnotyczny wobec ORM, wsparcie dla Doctrine i RedBean\u003C\/li\u003E\n\u003Cli\u003EREST-ful routing\u003C\/li\u003E\n\u003Cli\u003EGenerator CRUD\u003C\/li\u003E\n\u003Cli\u003EAgnostyczny wobec silnik\u00f3w szablon\u00f3w, wsparcie dla Twiga i czystego PHP\u003C\/li\u003E\n\u003Cli\u003EAutentykacja i autoryzacja\u003C\/li\u003E\n\u003Cli\u003E\u0141atwa konfiguracja w YAML-u\u003C\/li\u003E\n\u003Cli\u003ETaki konsolowe dzi\u0119ki Symfony Console\u003C\/li\u003E\n\u003Cli\u003EFormularze\u003C\/li\u003E\n\u003Cli\u003ELocalizacja\u003C\/li\u003E\n\u003Cli\u003ELogowanie z u\u017cyciem Monolog (zgodne z PSR-3)\u003C\/li\u003E\n\u003Cli\u003ECaching (zgodne z PSR-6)\u003C\/li\u003E\n\u003Cli\u003EKomunikaty flash\u003C\/li\u003E\n\u003C\/ul\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["framework","full-stack","micrus","php","plugins","programowanie"],"hasMore":true,"image":"https:\/\/avris.it\/image\/micrus_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/micrus_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/micrus_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022133.75\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EJak du\u017cy musi by\u0107 framework, aby umo\u017cliwia\u0142 szybkie, \u0142atwe i wygodne tworzenie \u0142adnie uporz\u0105dkowanych stron MVC? Aby by\u0142 \u0142atwo rozszerzalny i konfigurowalny?\u003C\/p\u003E\n\u003Cp\u003ENo w\u0142a\u015bnie wcale nie tak du\u017cy. Wypr\u00f3buj Micrusa!  Jego celem jest bycie tak ma\u0142ym, jak to tylko mo\u017cliwe, lecz oferowa\u0107 wszytkie najwa\u017cniejsze funkcjonalno\u015bci:\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/micrus_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/micrus_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022133.75\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EJak du\u017cy musi by\u0107 framework, aby umo\u017cliwia\u0142 szybkie, \u0142atwe i wygodne tworzenie \u0142adnie uporz\u0105dkowanych stron MVC? Aby by\u0142 \u0142atwo rozszerzalny i konfigurowalny?\u003C\/p\u003E\n\u003Cp\u003ENo w\u0142a\u015bnie wcale nie tak du\u017cy. Wypr\u00f3buj Micrusa!  Jego celem jest bycie tak ma\u0142ym, jak to tylko mo\u017cliwe, lecz oferowa\u0107 wszytkie najwa\u017cniejsze funkcjonalno\u015bci:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EZorientowany obiektowo\u003C\/li\u003E\n\u003Cli\u003EPrzejrzysta struktura MVC\u003C\/li\u003E\n\u003Cli\u003EKontener DI\u003C\/li\u003E\n\u003Cli\u003EEvent dispatching\u003C\/li\u003E\n\u003Cli\u003EAgnotyczny wobec ORM, wsparcie dla Doctrine i RedBean\u003C\/li\u003E\n\u003Cli\u003EREST-ful routing\u003C\/li\u003E\n\u003Cli\u003EGenerator CRUD\u003C\/li\u003E\n\u003Cli\u003EAgnostyczny wobec silnik\u00f3w szablon\u00f3w, wsparcie dla Twiga i czystego PHP\u003C\/li\u003E\n\u003Cli\u003EAutentykacja i autoryzacja\u003C\/li\u003E\n\u003Cli\u003E\u0141atwa konfiguracja w YAML-u\u003C\/li\u003E\n\u003Cli\u003ETaki konsolowe dzi\u0119ki Symfony Console\u003C\/li\u003E\n\u003Cli\u003EFormularze\u003C\/li\u003E\n\u003Cli\u003ELocalizacja\u003C\/li\u003E\n\u003Cli\u003ELogowanie z u\u017cyciem Monolog (zgodne z PSR-3)\u003C\/li\u003E\n\u003Cli\u003ECaching (zgodne z PSR-6)\u003C\/li\u003E\n\u003Cli\u003EKomunikaty flash\u003C\/li\u003E\n\u003C\/ul\u003E","words":118,"readTime":null,"lang":"pl"}}},"projects\/qc-quite-concise-programming-language":{"key":"projects\/qc-quite-concise-programming-language","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:45+02:00","publishedAt":"2015-12-23T00:53:00+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/qc.avris.it\/","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/QC","displayUrl":null}],"category":"projects","subcategory":null,"slug":"qc-quite-concise-programming-language"},"content":{"en":{"slug":"qc-quite-concise-programming-language","title":"QC \u2022 Quite Concise Programming Language","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/qc-quite-concise-programming-language_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022270.76923076923\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHaUlEQVRIiS2Vy64cZxVG13+pS1d1dZ+++PjENk5iOY6IcBKJSZiAEBEDJCaIB+AF4Bky4nV4AJCQEINMEhScxIljfD+XPqfvXd1V9V8ZnHzDNdmDvdf+xIOf\/S7KZIBIh3jnSNIeKu0T0oLx5AgrUwyaKDXDUZ+fvH\/Cn351j\/EgRyhJ4yJFqtBSIJXE+kjrAtYFAIwLNDZwMA7jA\/9+vuTxl09Zvb6kXe+w8zn4ltgswFyhPv3Dnz+z6Zh9C+geqrpBTEumb53wyS8f8mYPo35OJgUizThsWgZHBSejgl6myRNNABof2Znr4SGCC7A3gV3naU3g0bzh2abjpMq49ZMpk\/u3cbdu0lYTOJogygkkA8Rf\/vq3OF9s2TaO\/bbjeNpncmNMOqzQVUEdQWlJKRW71nE536MTRbdr+PDjO3x0e0gv0wgpCFHQhUDjAsZH9p3HW88X5zsendfcO+5xp58yzBSrxhJiYNUYVruOs7MVh0eP0aIq+PDBHZoQeXvS5\/a04mADWisSrYgIEiVxPtL5yHpv+O6ipl43nL7e8uibGTLTHN86YrE3FABlyovTLX6x4+i4Ii8SPj7pcVSmrK3n4mCZrVuEc0xKTXcwZIlG3L2NPqtbyhB4d1rRL3K01kx6iizV5KkmxIjzcDAeaT2BlPduVdTTAuMCb5YHNnvLctNQKcH2YHj5\/YxeT1P0FKE1vDlfU3rLf00gFjlOKVSe4q7WXC4X9MuEbFgiBejffvIeSmmqXkrVy0ArvJR4ITi4QKYknkiiJQiBDVBl0E81tfH0E0VPCX5YHvDG08bIw\/tj9KGl2dTcGaT849srTJ6QIvDNAYQiCInf7fH1nuXpEsweoRT6+KhkWGRordBakSca4yNaCfqZRgmBD5EQIokS1J2mNR4fIqebjidXV3xzeoXqDeg1az545x618ZxeSl4uWr56dAVKo6SiWWxI7Z7D9kAUAqklUimCc8QAuD161TlG\/ZxUSWyI5FpQZZpeqpBSEIEQr\/V1PpL\/yLeNo58IzON\/8bAoefb1K8Jb7\/N4ccykl1FWOfce3MTenbJc1jz955fI9QUH1xHTCqTAr3eIPEcojVLgjEG\/MykZlRlSSpRWZFoipcRGECHiQ8SFiPMRiNStx9hA3Xn21hNipLUWCZy\/WvL955+TFH2KG2P6gxJNZHW5JR0d4bIcZQ1aBryLMBwRtnO0FkjZI0SB+OL1ImZJgpKSALQuYkNEcB0bwLqA9YGD8bQ2EIkocc1PL2Zc\/O9b1Ml9frhc8fSZwbyakTiHcAaVJQzu3SXEgN3uiYcDyhl2sxnjk2N29YH9YolUikwZ9LpxZBb48VZ8hM5HXAQfIo0NbNYr3nz\/iLW7Xt84Txhnim1r2RjHpKoo7SWzbs9wdUq9X0C9I0sUrtXYHy4IR3d5+ME7tHXD4nyBM2MuX70mqyrSqsJ7T9d06CdXNWWaoJUkIggREilACFobeL3r+OZ8Q7ppmPYLrJB0xnJmHTsTuGojy90KrRNmy4a0zCmPMsgTknaDMzvSZsfVbMtXu5a86FHvG7I0g6RAtTuyVOCJGOnQf3+1YpAlVKlmmicsOserreGtMmWaJ+RK0DrNZX6f7zaO3emSNFFM5Bzn98gkZykUVSmZDnLODw6rBmxjRnQVYb9FRIfE0718zj7VxODpEAig83vq+TlCZoBAz2rL+daQJoq+EIQQMZ3n\/HSDaww6kaATmp2lO1\/inz7DbLdMTxyr5SVFohFHI4w3XJZ9dJkTREpoHHG3JtECLQTRB0y7xhw8SEXSH+JcQMkE9E2ynqDbzdC3BwnGRUIUTIuETeOotx2htSRS0i4O2OUOVx8I6y3oDJGXvHw1g2RCG0vePr7P+ZPvaN\/MkeUYqgyR9qBSDEYFRSKYn52jQkTIHYgItiVNJMSIyjO8rQneoN8tNKnSOAQekBH8pOQi0XSNIw4K4rXxyLJPWK2Jhw0UQ9RwTJJqRmHB8\/Ua0ZsQ2xa6+bWJeYke57x\/7yY3Jj109Lx5fcHF61O8a5EiR6U5g1HFdlaj0gydEBmnknGR8bK2nEVLS0QoiUwUItXEPIWiwC93iH0G\/SEizwlNQ7tc8J+zLWJwE5mkqGyK7ywST1873PKMemZJdE7dOm6fHLG6usQbT1ef4WvP1k7pT4\/J9BTFL\/74WVSSMlWYEAgIXi5b2sZhjMdzbRwICBFhHaQp0XkwFpwl2hZpDiQqkipIehm3TkY0reHmyQ2cSFDB4ro9aZ6z3x+QWLzURB\/x7RV33rpB2u+j68WGJz7w\/HJHL88ISvNgkpPekFztHRd7S2sjQUqs7xGEQK52iLIgFAVxn3H3+C6rFy+oFzNGpWM8SPB2A+2K+fmG3\/z651zMt7x49ozV14\/wXQMyASEoq4yurTCmBUBVg59+ZlEkVR\/\/4+\/xEeatI9EKlEBreV28VUo5KkiHJSJPkaM+cjSkPyz5\/acfEYsRtukYVBmLyyt6Gcxnc4z3HN864fTNFcEHbHdgND0hHU7pVWNQKTZK9nXN\/wECJSo73jElDwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/qc-quite-concise-programming-language_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022270.76923076923\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EThe idea is to create a \u003Cstrong\u003Esimple\u003C\/strong\u003E (in terms of complexity, not ease of use) programming language, that will have quite a \u003Cstrong\u003Econcise\u003C\/strong\u003E \u003Cstrong\u003Esyntax\u003C\/strong\u003E, that will play with the power of \u003Cstrong\u003EUnicode\u003C\/strong\u003E and most importantly \u2013 will be \u003Cstrong\u003Efun\u003C\/strong\u003E to create ;)\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/qc-quite-concise-programming-language_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022741\u0022 height=\u0022418\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHaUlEQVRIiS2Vy64cZxVG13+pS1d1dZ+++PjENk5iOY6IcBKJSZiAEBEDJCaIB+AF4Bky4nV4AJCQEINMEhScxIljfD+XPqfvXd1V9V8ZnHzDNdmDvdf+xIOf\/S7KZIBIh3jnSNIeKu0T0oLx5AgrUwyaKDXDUZ+fvH\/Cn351j\/EgRyhJ4yJFqtBSIJXE+kjrAtYFAIwLNDZwMA7jA\/9+vuTxl09Zvb6kXe+w8zn4ltgswFyhPv3Dnz+z6Zh9C+geqrpBTEumb53wyS8f8mYPo35OJgUizThsWgZHBSejgl6myRNNABof2Znr4SGCC7A3gV3naU3g0bzh2abjpMq49ZMpk\/u3cbdu0lYTOJogygkkA8Rf\/vq3OF9s2TaO\/bbjeNpncmNMOqzQVUEdQWlJKRW71nE536MTRbdr+PDjO3x0e0gv0wgpCFHQhUDjAsZH9p3HW88X5zsendfcO+5xp58yzBSrxhJiYNUYVruOs7MVh0eP0aIq+PDBHZoQeXvS5\/a04mADWisSrYgIEiVxPtL5yHpv+O6ipl43nL7e8uibGTLTHN86YrE3FABlyovTLX6x4+i4Ii8SPj7pcVSmrK3n4mCZrVuEc0xKTXcwZIlG3L2NPqtbyhB4d1rRL3K01kx6iizV5KkmxIjzcDAeaT2BlPduVdTTAuMCb5YHNnvLctNQKcH2YHj5\/YxeT1P0FKE1vDlfU3rLf00gFjlOKVSe4q7WXC4X9MuEbFgiBejffvIeSmmqXkrVy0ArvJR4ITi4QKYknkiiJQiBDVBl0E81tfH0E0VPCX5YHvDG08bIw\/tj9KGl2dTcGaT849srTJ6QIvDNAYQiCInf7fH1nuXpEsweoRT6+KhkWGRordBakSca4yNaCfqZRgmBD5EQIokS1J2mNR4fIqebjidXV3xzeoXqDeg1az545x618ZxeSl4uWr56dAVKo6SiWWxI7Z7D9kAUAqklUimCc8QAuD161TlG\/ZxUSWyI5FpQZZpeqpBSEIEQr\/V1PpL\/yLeNo58IzON\/8bAoefb1K8Jb7\/N4ccykl1FWOfce3MTenbJc1jz955fI9QUH1xHTCqTAr3eIPEcojVLgjEG\/MykZlRlSSpRWZFoipcRGECHiQ8SFiPMRiNStx9hA3Xn21hNipLUWCZy\/WvL955+TFH2KG2P6gxJNZHW5JR0d4bIcZQ1aBryLMBwRtnO0FkjZI0SB+OL1ImZJgpKSALQuYkNEcB0bwLqA9YGD8bQ2EIkocc1PL2Zc\/O9b1Ml9frhc8fSZwbyakTiHcAaVJQzu3SXEgN3uiYcDyhl2sxnjk2N29YH9YolUikwZ9LpxZBb48VZ8hM5HXAQfIo0NbNYr3nz\/iLW7Xt84Txhnim1r2RjHpKoo7SWzbs9wdUq9X0C9I0sUrtXYHy4IR3d5+ME7tHXD4nyBM2MuX70mqyrSqsJ7T9d06CdXNWWaoJUkIggREilACFobeL3r+OZ8Q7ppmPYLrJB0xnJmHTsTuGojy90KrRNmy4a0zCmPMsgTknaDMzvSZsfVbMtXu5a86FHvG7I0g6RAtTuyVOCJGOnQf3+1YpAlVKlmmicsOserreGtMmWaJ+RK0DrNZX6f7zaO3emSNFFM5Bzn98gkZykUVSmZDnLODw6rBmxjRnQVYb9FRIfE0718zj7VxODpEAig83vq+TlCZoBAz2rL+daQJoq+EIQQMZ3n\/HSDaww6kaATmp2lO1\/inz7DbLdMTxyr5SVFohFHI4w3XJZ9dJkTREpoHHG3JtECLQTRB0y7xhw8SEXSH+JcQMkE9E2ynqDbzdC3BwnGRUIUTIuETeOotx2htSRS0i4O2OUOVx8I6y3oDJGXvHw1g2RCG0vePr7P+ZPvaN\/MkeUYqgyR9qBSDEYFRSKYn52jQkTIHYgItiVNJMSIyjO8rQneoN8tNKnSOAQekBH8pOQi0XSNIw4K4rXxyLJPWK2Jhw0UQ9RwTJJqRmHB8\/Ua0ZsQ2xa6+bWJeYke57x\/7yY3Jj109Lx5fcHF61O8a5EiR6U5g1HFdlaj0gydEBmnknGR8bK2nEVLS0QoiUwUItXEPIWiwC93iH0G\/SEizwlNQ7tc8J+zLWJwE5mkqGyK7ywST1873PKMemZJdE7dOm6fHLG6usQbT1ef4WvP1k7pT4\/J9BTFL\/74WVSSMlWYEAgIXi5b2sZhjMdzbRwICBFhHaQp0XkwFpwl2hZpDiQqkipIehm3TkY0reHmyQ2cSFDB4ro9aZ6z3x+QWLzURB\/x7RV33rpB2u+j68WGJz7w\/HJHL88ISvNgkpPekFztHRd7S2sjQUqs7xGEQK52iLIgFAVxn3H3+C6rFy+oFzNGpWM8SPB2A+2K+fmG3\/z651zMt7x49ozV14\/wXQMyASEoq4yurTCmBUBVg59+ZlEkVR\/\/4+\/xEeatI9EKlEBreV28VUo5KkiHJSJPkaM+cjSkPyz5\/acfEYsRtukYVBmLyyt6Gcxnc4z3HN864fTNFcEHbHdgND0hHU7pVWNQKTZK9nXN\/wECJSo73jElDwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/qc-quite-concise-programming-language_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022741\u0022 height=\u0022418\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EThe idea is to create a \u003Cstrong\u003Esimple\u003C\/strong\u003E (in terms of complexity, not ease of use) programming language, that will have quite a \u003Cstrong\u003Econcise\u003C\/strong\u003E \u003Cstrong\u003Esyntax\u003C\/strong\u003E, that will play with the power of \u003Cstrong\u003EUnicode\u003C\/strong\u003E and most importantly \u2013 will be \u003Cstrong\u003Efun\u003C\/strong\u003E to create ;)\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["consise","esoteric","j\u0119zyk","language","php","programming","programming language","programowanie","qc"],"hasMore":false,"image":"https:\/\/avris.it\/image\/qc-quite-concise-programming-language_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/qc-quite-concise-programming-language_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/qc-quite-concise-programming-language_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022135.38461538462\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EThe idea is to create a \u003Cstrong\u003Esimple\u003C\/strong\u003E (in terms of complexity, not ease of use) programming language, that will have quite a \u003Cstrong\u003Econcise\u003C\/strong\u003E \u003Cstrong\u003Esyntax\u003C\/strong\u003E, that will play with the power of \u003Cstrong\u003EUnicode\u003C\/strong\u003E and most importantly \u2013 will be \u003Cstrong\u003Efun\u003C\/strong\u003E to create ;)\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/qc-quite-concise-programming-language_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/qc-quite-concise-programming-language_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022135.38461538462\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EThe idea is to create a \u003Cstrong\u003Esimple\u003C\/strong\u003E (in terms of complexity, not ease of use) programming language, that will have quite a \u003Cstrong\u003Econcise\u003C\/strong\u003E \u003Cstrong\u003Esyntax\u003C\/strong\u003E, that will play with the power of \u003Cstrong\u003EUnicode\u003C\/strong\u003E and most importantly \u2013 will be \u003Cstrong\u003Efun\u003C\/strong\u003E to create ;)\u003C\/p\u003E","words":40,"readTime":null,"lang":"en"}}},"projects\/can-i-go-home-now":{"key":"projects\/can-i-go-home-now","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:45+02:00","publishedAt":"2015-12-10T13:39:00+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/canigohome.avris.it\/","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/GoHome","displayUrl":null}],"category":"projects","subcategory":null,"slug":"can-i-go-home-now"},"content":{"en":{"slug":"can-i-go-home-now","title":"Can I go home now?","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022239.24882629108\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGbklEQVRIiV2WuW4TXxuHn5kzS+xxbMd2Fi8xTkgiBAWhAAmFCCgiKGhYGi6Aq6DJTXADFAiJkooOmoQKCMIgpKBAEi\/xJHa8jGc861cgRvp\/U56RzvZ7zvO+0rt37yLXdWk0Guzv73N4eEij0aBQKHDr1i10XefLly\/UajWCIKBcLjM\/P08ymcQwDCRJwjAMyuUyAJ1Oh0KhgBACgDAMiaIIWZYxDIMgCBgMBkiSxGQy4cePH+RyOXzfp9VqoaiqyqtXr+j3+xwdHXFycsLdu3fJZrO8fv2alZUV7t27R7PZxLIsjo6OODs7QwhBpVJhbm4Ox3EIw5B8Po9hGLiui6qqSJJEGIaEYUgmkwHAcZx4g0EQMB6PEUIghCAIApSPHz9Sr9dxXZd8Ps\/t27f59OkT79+\/J5\/Ps7y8jO\/7rK+vc3BwQBAEHB8fA1AsFomiCMdxME0zvi0ASZKQZZkoikgmkwghcF0Xx3Hicd\/3MQyDZDJJo9HAcRxEtVrd\/vz5M2tra2xsbPDy5Uva7TbXrl1jeXmZhYUFgiBgOBxSKpUAEEKgqipCCMIwpFQqMT09jaIoWJaFrusAFAoFoigiCAISiQTn5+eYpkkikUBRFPr9Pp1OJ57PdV2UbrfLs2fPaLVavHnzBs\/zWFpaIpfLsbu7C8DMzAySJHF2dkalUsFxHEajEZIkoaoq37594+rVqwCUSiXS6XQcSSqVQpIk\/v8bDAZ4nkcQBERRRLPZpFgsIjRN2378+DEvXrxACMFoNCKZTLK3t4dpmqytraGqKr7v4zgOtm2ztLREJpNBURT+\/PnD6ekppVIJWZYxTRMAXddRFIUgCPB9nyAIcF2XbreLpmlkMhnG4zG9Xg\/f97EsCwB5amqKTqdDLpej0+lgWRYHBwckEgkymQypVCqGLpvNIoTAtm2EEDFL09PT9Pt9PM\/D933a7Tau68ZRRFGEaZpYloUQgkwmQxiGDIdDbNtmMpkgyzKj0QhlcXGR58+f8\/TpU6Iool6vI4RgOBySy+XQdR3DMBBCkMvlkGWZbDaLJEmkUimCIIg3ValU4n+apiFJElEUoaoqxWKRTqeDruuEYYjv+zFfsiyjqiqmaSL29\/e3wzDk69ev3Lx5k3Q6TavVIpVK0e12WVlZIZ1Ok06nmZ2dpVKp\/Of1HB8fx4tOJhMGgwG9Xg9FUUgmk0wmE2zbJgxDxuMxh4eHNJtNRqMRg8EA3\/dJpVJEUfQ3CVVVt\/\/Jq16vU6vVWFlZod1uk0wmWV9fJ5PJkMlkYrgVRUFVVTzPo1QqMZlMGA6HDAYD2u02p6endLtdhBBEUYRlWfi+j+u61Ot1wjDEdV1s22ZqaoowDJmbm\/ubhKqq257nxQAeHR2haRqbm5t0Oh0uX77MhQsXmJ6exrZtHMchCAJmZmZQFOVv7opCuzuicXhAr9fDNE0cx0FRFDzPw7btWBPtdpswDAHQNC3G4t+YAqCqKqqqIssyruvy8+dPPM\/jwYMHzM\/P47oug8EAXdfxfT+ePJ\/PM5lMODw8pFKugjvC933m5uYoFAo0m02GwyGLi4sIIZBlGUVRSCQSWJaFpmn0ej263S6GYZDP51GEEExNTREEQfwioiji169f\/P79O2YhDEMKhQKzs7NIkkS328W2bTzP4\/z8HNd1WV1djQ28uroKwM7ODslkkmKxCMDe3h7VapVisYiu6\/R6PRKJBLlc7q8Yx+MxhmHgeR7pdBrf95FlmStXrnBwcMDi4iKqqsZ2\/ReX67qcnp7G9cuyLFRV5eTkBNM0GY\/HhGGI4zh0Oh16vR75fJ5yuYymaWiahq7rJJNJbNvm\/PycQqGABESqqsYykySJra0tTk5OODk5wbZtxuMxiUQCx3HQNI3JZEK5XMayLC5dukS9XscwDGq1GsPhkO\/fv8cHK5fLTE9Ps76+zo0bN5BlmX6\/T6lUiotyo9GgVqthGAayLMux0BYWFnjy5Ak7Ozvs7Ozgui6SJBEEAaPRCF3XUVWVfD4fl490Os2jR4+4ePEiHz58QJIkNjY2CMMQWZapVqtsbW3x8OFDNjc3Y5Zc1yWbzcbdwXg8\/lv579y5s22aJvfv30dRFN6+fctkMolbhX9Q+74fC83zPBzHYW5ujoWFBSqVCru7u\/T7fVqtFrlcjuvXr+N5HsvLy1SrVVZXVxmNRjHM\/3opx3GoVquxy\/4H69Nv42Fs0AsAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022239.24882629108\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022478.49765258216\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGbklEQVRIiV2WuW4TXxuHn5kzS+xxbMd2Fi8xTkgiBAWhAAmFCCgiKGhYGi6Aq6DJTXADFAiJkooOmoQKCMIgpKBAEi\/xJHa8jGc861cgRvp\/U56RzvZ7zvO+0rt37yLXdWk0Guzv73N4eEij0aBQKHDr1i10XefLly\/UajWCIKBcLjM\/P08ymcQwDCRJwjAMyuUyAJ1Oh0KhgBACgDAMiaIIWZYxDIMgCBgMBkiSxGQy4cePH+RyOXzfp9VqoaiqyqtXr+j3+xwdHXFycsLdu3fJZrO8fv2alZUV7t27R7PZxLIsjo6OODs7QwhBpVJhbm4Ox3EIw5B8Po9hGLiui6qqSJJEGIaEYUgmkwHAcZx4g0EQMB6PEUIghCAIApSPHz9Sr9dxXZd8Ps\/t27f59OkT79+\/J5\/Ps7y8jO\/7rK+vc3BwQBAEHB8fA1AsFomiCMdxME0zvi0ASZKQZZkoikgmkwghcF0Xx3Hicd\/3MQyDZDJJo9HAcRxEtVrd\/vz5M2tra2xsbPDy5Uva7TbXrl1jeXmZhYUFgiBgOBxSKpUAEEKgqipCCMIwpFQqMT09jaIoWJaFrusAFAoFoigiCAISiQTn5+eYpkkikUBRFPr9Pp1OJ57PdV2UbrfLs2fPaLVavHnzBs\/zWFpaIpfLsbu7C8DMzAySJHF2dkalUsFxHEajEZIkoaoq37594+rVqwCUSiXS6XQcSSqVQpIk\/v8bDAZ4nkcQBERRRLPZpFgsIjRN2378+DEvXrxACMFoNCKZTLK3t4dpmqytraGqKr7v4zgOtm2ztLREJpNBURT+\/PnD6ekppVIJWZYxTRMAXddRFIUgCPB9nyAIcF2XbreLpmlkMhnG4zG9Xg\/f97EsCwB5amqKTqdDLpej0+lgWRYHBwckEgkymQypVCqGLpvNIoTAtm2EEDFL09PT9Pt9PM\/D933a7Tau68ZRRFGEaZpYloUQgkwmQxiGDIdDbNtmMpkgyzKj0QhlcXGR58+f8\/TpU6Iool6vI4RgOBySy+XQdR3DMBBCkMvlkGWZbDaLJEmkUimCIIg3ValU4n+apiFJElEUoaoqxWKRTqeDruuEYYjv+zFfsiyjqiqmaSL29\/e3wzDk69ev3Lx5k3Q6TavVIpVK0e12WVlZIZ1Ok06nmZ2dpVKp\/Of1HB8fx4tOJhMGgwG9Xg9FUUgmk0wmE2zbJgxDxuMxh4eHNJtNRqMRg8EA3\/dJpVJEUfQ3CVVVt\/\/Jq16vU6vVWFlZod1uk0wmWV9fJ5PJkMlkYrgVRUFVVTzPo1QqMZlMGA6HDAYD2u02p6endLtdhBBEUYRlWfi+j+u61Ot1wjDEdV1s22ZqaoowDJmbm\/ubhKqq257nxQAeHR2haRqbm5t0Oh0uX77MhQsXmJ6exrZtHMchCAJmZmZQFOVv7opCuzuicXhAr9fDNE0cx0FRFDzPw7btWBPtdpswDAHQNC3G4t+YAqCqKqqqIssyruvy8+dPPM\/jwYMHzM\/P47oug8EAXdfxfT+ePJ\/PM5lMODw8pFKugjvC933m5uYoFAo0m02GwyGLi4sIIZBlGUVRSCQSWJaFpmn0ej263S6GYZDP51GEEExNTREEQfwioiji169f\/P79O2YhDEMKhQKzs7NIkkS328W2bTzP4\/z8HNd1WV1djQ28uroKwM7ODslkkmKxCMDe3h7VapVisYiu6\/R6PRKJBLlc7q8Yx+MxhmHgeR7pdBrf95FlmStXrnBwcMDi4iKqqsZ2\/ReX67qcnp7G9cuyLFRV5eTkBNM0GY\/HhGGI4zh0Oh16vR75fJ5yuYymaWiahq7rJJNJbNvm\/PycQqGABESqqsYykySJra0tTk5OODk5wbZtxuMxiUQCx3HQNI3JZEK5XMayLC5dukS9XscwDGq1GsPhkO\/fv8cHK5fLTE9Ps76+zo0bN5BlmX6\/T6lUiotyo9GgVqthGAayLMux0BYWFnjy5Ak7Ozvs7Ozgui6SJBEEAaPRCF3XUVWVfD4fl490Os2jR4+4ePEiHz58QJIkNjY2CMMQWZapVqtsbW3x8OFDNjc3Y5Zc1yWbzcbdwXg8\/lv579y5s22aJvfv30dRFN6+fctkMolbhX9Q+74fC83zPBzHYW5ujoWFBSqVCru7u\/T7fVqtFrlcjuvXr+N5HsvLy1SrVVZXVxmNRjHM\/3opx3GoVquxy\/4H69Nv42Fs0AsAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022478.49765258216\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["assetic","countdown","free time","javascript","job","js","micrus","php","programming","programowanie","weekend"],"hasMore":false,"image":"https:\/\/avris.it\/image\/can-i-go-home-now_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022119.62441314554\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022119.62441314554\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E","words":19,"readTime":null,"lang":"en"}}},"blog\/technology\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji":{"key":"blog\/technology\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:44+02:00","publishedAt":"2015-11-15T00:07:00+01:00","group":null,"category":"blog","subcategory":"technology","slug":"proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji"},"content":{"pl":{"slug":"proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji","title":"Proste potwierdzenie w JavaScripcie, a rozdzielenie warstw aplikacji","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022268.48780487805\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEo0lEQVRIib2WS4\/l1BGAvzoP2\/f6PvtB98AwPfRoIkE2JLCJlCChSInEht+BWOVPBGUb\/k8UKSEPokiwIauMEMOgnu5hOt3X9vXj+FQWvj28pi\/DIqnNsc+pcn1Vripbfvve7zRNE1AFEVClrCrycQ4oddOSZSn\/L3F\/\/\/BDfnT3Dvfvf07oOkZ5TuharHVEhXVRcPv4mPliwXSS\/++B3vjFzwE4PLzxncO+D\/S9kiT+mR7W1GsuLgsmk5wYIwKIsaRZyrqqEAEwm1XxPqUsVozGOXW9Zjqd4rY5sNZh7bNH533Czs4OqnHYUEUBI0KWZWhUEJCNvrGGfDLBGoubTBAR3D\/+9tfBuULcaJorDwoIqAxnUUGu9vQrXQWuuFWGjat1swxgQA9Y73n9tdcHe\/PEGwDus3v\/xhhD3zb4xBNjjxXLYr5gthyi7bqAEWgZgORrEBFFjWA2sBHdAAkRMKpMFgsenpzw+IsHmDSjaOonQN8W18UGgxAk0MUeEyImNfzq7bd4593fPPv7+h5569dvQmjIkpQQr9dzl7Ma3yghF9QprhaCV2o6ROR6y6eIql5rU60uKLVnVZwzdePrgUaXyqhSnEInytopgqAtVGXJ6dkjUKVeVxjryVJP0wacH6om9pG2bTEiQ0d5S90FVJVRlqIi3D46Iu2hFEgEvlU23wQyZWSthpeWMy7WNbkKJ21NH2Gc5xyNh2hEBN1U8g+9Bug3iUsjX7XZ04AEw2KSMZ5mHN3a53HVkdYtUSMhhOstf6CsDIwFlledeh2Qc5bjecLB7ojRfM7zLx\/zyccfYVSpqmqrk3uPalQjsgl5MnLMffxGZpxzOOdAYF+HDG0bbe6Vg5y9vRliDX3XEpuanfmCw9nse4v6wZcrZqbh4dkZL968SdGkuHHg9OEJRbFmb3+f\/f1dvPfkEVzYzLJ+C1AbIYSeto2Uj1aEk3Pu3H2Z3cViKwzAz+7uo8Ard24CYAUEZblcPtG5CkoiBB2yc7klRa5qAqfnNYk1PH\/4Aqo9jsg\/\/\/gH3n\/\/99jNuA0GWrEoCQZBVJl0HWrCMMUjdAa6ONSsN4NNzZCVplqRCSQKflsNjZ1jb+xIfMK6uKBtwTlLJynPzRbc\/+wehkgwsLaGQmBaK8tG6YAygcoPTjvAINRWEYVmc69RsYCYIUPzbW1\/9p+CxAi7S8fqvMBYR914Znu7\/OSXr3F8fsr64jFdH9jdP2Bdlnzwpz\/TdJc4gWBhbcFESKLQGMUgmKjc6KAwyjoRrCqjCJlu7XpMsA69cYtV78lmjmziKC4r6qpEtGM2TZn5hqUPjLxl9\/CQn776KohQGFgLjOPwRceCNeCBpRpmETKBnQh7CDvRMFYIW5DcWW9xnz\/AWOU5C8XlJc5Y0r2K9qO\/YAj0XY1NUtqmJ5\/kHEwNx3du8vGn9wk99D2MRDBGGFnDCEsOnNqWqUvotcfHSOYcKw+1vf6dOQ0N2XjJ8e0Dvvj0hLotufvj28xvHZFmGesvH\/Hgk3+Rj5RYPqQrcyS07IwMdpJRNjX0YH3CC9mYPRU6oPeKj54XJzNWdU1Jj7eOcYwM\/wpPl\/8CWIcTbntq1pMAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022268.48780487805\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022615\u0022 height=\u0022344\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEo0lEQVRIib2WS4\/l1BGAvzoP2\/f6PvtB98AwPfRoIkE2JLCJlCChSInEht+BWOVPBGUb\/k8UKSEPokiwIauMEMOgnu5hOt3X9vXj+FQWvj28pi\/DIqnNsc+pcn1Vripbfvve7zRNE1AFEVClrCrycQ4oddOSZSn\/L3F\/\/\/BDfnT3Dvfvf07oOkZ5TuharHVEhXVRcPv4mPliwXSS\/++B3vjFzwE4PLzxncO+D\/S9kiT+mR7W1GsuLgsmk5wYIwKIsaRZyrqqEAEwm1XxPqUsVozGOXW9Zjqd4rY5sNZh7bNH533Czs4OqnHYUEUBI0KWZWhUEJCNvrGGfDLBGoubTBAR3D\/+9tfBuULcaJorDwoIqAxnUUGu9vQrXQWuuFWGjat1swxgQA9Y73n9tdcHe\/PEGwDus3v\/xhhD3zb4xBNjjxXLYr5gthyi7bqAEWgZgORrEBFFjWA2sBHdAAkRMKpMFgsenpzw+IsHmDSjaOonQN8W18UGgxAk0MUeEyImNfzq7bd4593fPPv7+h5569dvQmjIkpQQr9dzl7Ma3yghF9QprhaCV2o6ROR6y6eIql5rU60uKLVnVZwzdePrgUaXyqhSnEInytopgqAtVGXJ6dkjUKVeVxjryVJP0wacH6om9pG2bTEiQ0d5S90FVJVRlqIi3D46Iu2hFEgEvlU23wQyZWSthpeWMy7WNbkKJ21NH2Gc5xyNh2hEBN1U8g+9Bug3iUsjX7XZ04AEw2KSMZ5mHN3a53HVkdYtUSMhhOstf6CsDIwFlledeh2Qc5bjecLB7ojRfM7zLx\/zyccfYVSpqmqrk3uPalQjsgl5MnLMffxGZpxzOOdAYF+HDG0bbe6Vg5y9vRliDX3XEpuanfmCw9nse4v6wZcrZqbh4dkZL968SdGkuHHg9OEJRbFmb3+f\/f1dvPfkEVzYzLJ+C1AbIYSeto2Uj1aEk3Pu3H2Z3cViKwzAz+7uo8Ard24CYAUEZblcPtG5CkoiBB2yc7klRa5qAqfnNYk1PH\/4Aqo9jsg\/\/\/gH3n\/\/99jNuA0GWrEoCQZBVJl0HWrCMMUjdAa6ONSsN4NNzZCVplqRCSQKflsNjZ1jb+xIfMK6uKBtwTlLJynPzRbc\/+wehkgwsLaGQmBaK8tG6YAygcoPTjvAINRWEYVmc69RsYCYIUPzbW1\/9p+CxAi7S8fqvMBYR914Znu7\/OSXr3F8fsr64jFdH9jdP2Bdlnzwpz\/TdJc4gWBhbcFESKLQGMUgmKjc6KAwyjoRrCqjCJlu7XpMsA69cYtV78lmjmziKC4r6qpEtGM2TZn5hqUPjLxl9\/CQn776KohQGFgLjOPwRceCNeCBpRpmETKBnQh7CDvRMFYIW5DcWW9xnz\/AWOU5C8XlJc5Y0r2K9qO\/YAj0XY1NUtqmJ5\/kHEwNx3du8vGn9wk99D2MRDBGGFnDCEsOnNqWqUvotcfHSOYcKw+1vf6dOQ0N2XjJ8e0Dvvj0hLotufvj28xvHZFmGesvH\/Hgk3+Rj5RYPqQrcyS07IwMdpJRNjX0YH3CC9mYPRU6oPeKj54XJzNWdU1Jj7eOcYwM\/wpPl\/8CWIcTbntq1pMAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022615\u0022 height=\u0022344\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Ehref\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-attr\u0022\u003Eonclick\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022return confirm(\u0027{{ \u0027delete.confirm\u0027|l|e }}\u0027)\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    {{ \u0027delete\u0027|l }}\n\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EProsta sprawa \u2013 linkujemy do adresu, kt\u00f3ry usunie produkt z bazy, ale przy klikni\u0119ciu pytamy u\u017cytkownika, czy na pewno chce to zrobi\u0107. Je\u015bli nie chce, wtedy \u003Ccode\u003Econfirm()\u003C\/code\u003E zwr\u00f3ci \u003Ccode\u003Efalse\u003C\/code\u003E, a wi\u0119c wykonanie przekierowania zostanie zablokowane.\u003C\/p\u003E\n\u003Cp\u003EJest z tym kodem tylko jeden problem \u2013 mieszamy ze sob\u0105 HTML i JS. A to nie tak powinny dzia\u0142a\u0107 internety.\u003C\/p\u003E\n\u003Cp\u003EPoprawnie napisana strona internetowa sk\u0142ada si\u0119 (oczywi\u015bcie w cz\u0119\u015bci frontendowej) z trzech warstw:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ew HTML-u umieszczamy \u003Cstrong\u003Eustrukturyzowane dane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ew CSS-ach definiujemy, jak te dane maj\u0105 by\u0107 \u003Cstrong\u003Eprezentowane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ea w JS-ie dodajemy wszystkie te \u003Cstrong\u003Efajerwerki\u003C\/strong\u003E i \u015bwiecide\u0142ka, dzi\u0119ki kt\u00f3rym strona jest dynamiczniejsza i atrakcyjniejsza.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003ENajlepiej, gdyby warstwy te w og\u00f3le si\u0119 ze sob\u0105 nie miesza\u0142y. Dzi\u0119ki temu kod jest czystszy, a warstwy mog\u0105 by\u0107 u\u017cywane i modyfikowane niezale\u017cnie od siebie. Mo\u017cna na przyk\u0142ad w banalnie prosty spos\u00f3b zaimplementowa\u0107 r\u00f3\u017cne sk\u00f3rki na stronie, po prostu podmieniaj\u0105c u\u017cywany akrusz styl\u00f3w na inny. Je\u015bli w HTML-u nie umie\u015bcimy \u017cadnych styl\u00f3w inline (mam nadziej\u0119, \u017ce nikomu cho\u0107 troch\u0119 znaj\u0105cemu temat nie trzeba t\u0142umaczy\u0107, jak z\u0142y jest to pomys\u0142), lecz tylko dane oraz struktur\u0119, w jakiej s\u0105 u\u0142o\u017cone, to ca\u0142kowita zmiana wygl\u0105du strony jest nadzwyczaj \u0142atwa. (Dla przyk\u0142adu cho\u0107by \u003Ca href=\u0022http:\/\/bootswatch.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E bootswatch.com\u003C\/a\u003E albo \u003Ca href=\u0022http:\/\/www.csszengarden.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E csszengarden.com\u003C\/a\u003E \u2013 wszystkie podstrony w dziale \u201cthemes\u201d r\u00f3\u017cni\u0105 si\u0119 tylko jedn\u0105 rzecz\u0105: nazw\u0105 pliku .css)\u003C\/p\u003E\n\u003Cp\u003EDok\u0142adnie to samo tyczy si\u0119 JavaScriptu. Je\u015bli kod wykonywalny umie\u015bcimy bezpo\u015brednio wewn\u0105trz znacznika HTML, nasz kod staje si\u0119 zdecydowanie mniej czytelny i bardziej nara\u017cony na powtarzalno\u015b\u0107. Wprowadzanie w nim potem zmian mo\u017ce si\u0119 okaza\u0107 drog\u0105 przez m\u0119k\u0119. Powiedzmy, \u017ce po jakim\u015b czasie zechcemy zmieni\u0107 to brzydkie okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E na przyk\u0142ad na bootstrapowy \u003Ca href=\u0022http:\/\/getbootstrap.com\/javascript\/#modals\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E modal\u003C\/a\u003E. B\u0119dziemy wtedy musieli znale\u017a\u0107 wszystkie u\u017cycia podobnego kodu w naszym projekcie i przerobi\u0107 ka\u017cde z nich. Po co si\u0119 tak m\u0119czy\u0107?\u003C\/p\u003E\n\u003Cp\u003ENatkn\u0105\u0142em si\u0119 ostatnio na taki oto kod, maj\u0105cy wykona\u0107 nasze proste zadanie bez mieszania ze sob\u0105 warstw aplikacji:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Eclass\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022js-delete-event\u0022\u003C\/span\u003E \n    \u003Cspan class=\u0022hljs-attr\u0022\u003Ehref\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022javascript:void(0)\u0022\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-attr\u0022\u003Edata-delete-url\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-attr\u0022\u003Edata-confirm-message\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    {{ \u0027delete\u0027|l }}\n\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ENatomiast w pliku JavaScriptu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.js-delete-event\u0027\u003C\/span\u003E).on(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (\u003Cspan class=\u0022hljs-literal\u0022\u003Etrue\u003C\/span\u003E == confirm($(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).data(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027confirm-message\u0027\u003C\/span\u003E))) {\n        \u003Cspan class=\u0022hljs-built_in\u0022\u003Ewindow\u003C\/span\u003E.location.href = $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).data(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027delete-url\u0027\u003C\/span\u003E);\n    }\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWygl\u0105da na zdecydowanie bardziej skomplikowany ni\u017c powien by\u0107... Niby jest w porz\u0105dku: w HTML-u nie mamy skrypt\u00f3w, a jedno z drugim komunikuje si\u0119 za pomoc\u0105 klas i atrybut\u00f3w \u003Ccode\u003Edata\u003C\/code\u003E, tak jak powinno by\u0107. HTML definiuje, \u017ce link jest klasy \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E, dok\u0105d powinien kierowa\u0107 i jak brzmi przet\u0142umaczona pro\u015bba o potwierdzenie, natomiast JS szuka wszystkich element\u00f3w z klas\u0105 \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E i podpina pod nie listenera, kt\u00f3ry o potwierdzenie faktycznie spyta, i w zale\u017cno\u015bci od odpowiedzi, przekierowuje u\u017cytkownika do strony usuwaj\u0105cej, b\u0105d\u017a te\u017c nie.\u003C\/p\u003E\n\u003Cp\u003EA jednak JS w tym HTML-owym kodzie si\u0119 pojawia, i to w swojej najbrzydszej formie: jako pseudoprotok\u00f3\u0142. Link, zamiast kierowa\u0107 nas do rzeczywistej strony, odsy\u0142a nas do jakiego\u015b \u003Ccode\u003Evoid(0)\u003C\/code\u003E przez nieistniej\u0105cy protok\u00f3\u0142 \u003Ccode\u003Ejavascript\u003C\/code\u003E... Jest to zwyk\u0142y zabieg maj\u0105cy na celu zablokowanie linka, skierowanie go donik\u0105d, ale jak\u017ce strasznie psuje semantyk\u0119 strony...\u003C\/p\u003E\n\u003Cp\u003EI ma w dupie \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Progressive_enhancement\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Progressive enhancement\u003C\/a\u003E. A to bardzo \u017ale, mie\u0107 go w dupie...\u003C\/p\u003E\n\u003Cp\u003EW progressive enhancement chodzi mniej wi\u0119cej o to, aby zapewni\u0107 dost\u0119p do wszystkich podstawowych danych na stronie oraz do wszystkich podstawowych funkcji naszej aplikacji dla \u003Cstrong\u003Eka\u017cdego\u003C\/strong\u003E u\u017cytkownika. Nawet je\u015bli u\u017cywa IE6 albo nie daj bogini jakiego\u015b lynxa czy innej wy\u0142\u0105cznie tekstowej przegl\u0105darki. Natomiast im jego przegl\u0105darka jest lepsza, nowocze\u015bniejsza i zgodniejsza ze standardami, tym wi\u0119cej deweloper mo\u017ce zaszale\u0107 z \u0142adnym wygl\u0105dem i wodotryskami.\u003C\/p\u003E\n\u003Cp\u003ENie zawsze u\u017cytkownikowi zadzia\u0142aj\u0105 skrypty. Mo\u017ce CDN z jak\u0105\u015b bibliotek\u0105 zaszwankuje, mo\u017ce user jedzie poci\u0105giem i mu net przerywa, a mo\u017ce po prostu sam je wy\u0142\u0105czy\u0142 (tak, niekt\u00f3rzy to robi\u0105).\u003C\/p\u003E\n\u003Cp\u003EJak w takim przypadku zadzia\u0142a powy\u017cszy kod? Ano w\u0142a\u015bnie, nie zadzia\u0142a w og\u00f3le. Chyba \u017ce user zajrzy w \u017ar\u00f3d\u0142o strony, domy\u015bli si\u0119, o co chodzi, i r\u0119cznie przejdzie do URL-a podanego w atrybucie \u003Ccode\u003Edata-delete-url\u003C\/code\u003E. Powodzenia.\u003C\/p\u003E\n\u003Cp\u003EA wi\u0119c progressive enhancement le\u017cy. Dla pewnej grupy u\u017cytkownik\u00f3w dost\u0119p do wa\u017cnej funkcjonalno\u015bci jest niemo\u017cliwy.\u003C\/p\u003E\n\u003Cp\u003ESp\u00f3jrzmy teraz na inny kod:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Ehref\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\u003C\/span\u003E \n    \u003Cspan class=\u0022hljs-attr\u0022\u003Edata-confirm\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    {{ \u0027delete\u0027|l }}\n\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027a[data-confirm]\u0027\u003C\/span\u003E).click(\u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E confirm($(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).data(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027confirm\u0027\u003C\/span\u003E));\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETutaj mamy w HTML-u najzwyczajniejszy w \u015bwiecie link, po prostu z jednym dodatkowym atrybutem. Gdyby z jakiego\u015b powodu nie za\u0142adowa\u0142 si\u0119 skypt, \u015bwiat si\u0119 nie zawali. U\u017cytkownik dalej ma mo\u017cliwo\u015b\u0107 usuni\u0119cia elementu, po prostu jest bardziej nara\u017cony na zrobienie tego przez przypadek, bo nie zobaczy potwierdzenia.\u003C\/p\u003E\n\u003Cp\u003EJe\u015bli natomiast JS dzia\u0142a, skrypt znajdzie wszystkie elementy posiadaj\u0105ce atrybut \u003Ccode\u003Edata-confirm\u003C\/code\u003E i podepnie pod nie listenera, zadaj\u0105cego u\u017cytkownikowi pytanie, kt\u00f3re si\u0119 w tym atrybucie znajduje.\u003C\/p\u003E\n\u003Cp\u003ETen kod jest o wiele lepszy od poprzedniego nie tylko ze wzgl\u0119du na respektowanie progressive enhancement:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EElement A zosta\u0142 odchudzony ze wszystkich zb\u0119dnych atrybut\u00f3w (czyli po\u0142owy!). W poprzednim kodzie jego autor uda\u0142, \u017ce link donik\u0105d nie kieruje, tylko po to, by p\u00f3\u017aniej przekaza\u0107 odpowiedni URL w osbobnym atrybucie. U\u017cy\u0142 te\u017c specjalnej klasy, po kt\u00f3rej JS mia\u0142 rozpozna\u0107 interesuj\u0105ce go elementy, mimo \u017ce sam fakt posiadania tekstu potwierdzenia ju\u017c dostatecznie jasno identyfikuje elementy, kt\u00f3re powinny wy\u015bwietli\u0107 potwierdzenie.\u003C\/li\u003E\n\u003Cli\u003EWykorzystanli\u015bmy \u015bwietnego ficzera jQuery \u2013 to, \u017ce zwr\u00f3cenie \u003Ccode\u003Efalse\u003C\/code\u003E w event hadlerze automatycznie zatrzymuje propagacj\u0119 zdarzenia. W bardzo elegancki i zwi\u0119z\u0142y spos\u00f3b zatrzymali\u015bmy przekierowanie po klikni\u0119ciu, bez potrzeby uciekania si\u0119 do pseudoprotoko\u0142\u00f3w ani \u003Ccode\u003Eevent.stoppropagation(); event.preventdefault();\u003C\/code\u003E, przy okazji jeszcze pytaj\u0105c o zgod\u0119 u\u017cytkownika \u2013 w jednej prostej linijce!\u003C\/li\u003E\n\u003Cli\u003ENie u\u017cywamy okropnego \u003Ccode\u003Ewindow.location.href\u003C\/code\u003E. Pozwalamy na zwyczajn\u0105 obs\u0142ug\u0119 operacji przekierowania po klikni\u0119ciu w link, po prostu rozszerzaj\u0105c j\u0105 o mo\u017cliwo\u015b\u0107 warunkowego przerwania, zamiast sztucznie i nieelegancko blokowa\u0107 przekierowanie tylko po to, by potem jeszcze sztuczniej wywo\u0142a\u0107 je od nowa...\u003C\/li\u003E\n\u003C\/ul\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["html","javascript","js","programowanie","progressive enhancement","warstwy abstracji","web"],"hasMore":true,"image":"https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022134.24390243902\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022134.24390243902\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;a href=\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\n    onclick=\u0022return confirm(\u0027{{ \u0027delete.confirm\u0027|l|e }}\u0027)\u0022\u0026gt;\n    {{ \u0027delete\u0027|l }}\n\u0026lt;\/a\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EProsta sprawa \u2013 linkujemy do adresu, kt\u00f3ry usunie produkt z bazy, ale przy klikni\u0119ciu pytamy u\u017cytkownika, czy na pewno chce to zrobi\u0107. Je\u015bli nie chce, wtedy \u003Ccode\u003Econfirm()\u003C\/code\u003E zwr\u00f3ci \u003Ccode\u003Efalse\u003C\/code\u003E, a wi\u0119c wykonanie przekierowania zostanie zablokowane.\u003C\/p\u003E\n\u003Cp\u003EJest z tym kodem tylko jeden problem \u2013 mieszamy ze sob\u0105 HTML i JS. A to nie tak powinny dzia\u0142a\u0107 internety.\u003C\/p\u003E\n\u003Cp\u003EPoprawnie napisana strona internetowa sk\u0142ada si\u0119 (oczywi\u015bcie w cz\u0119\u015bci frontendowej) z trzech warstw:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ew HTML-u umieszczamy \u003Cstrong\u003Eustrukturyzowane dane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ew CSS-ach definiujemy, jak te dane maj\u0105 by\u0107 \u003Cstrong\u003Eprezentowane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ea w JS-ie dodajemy wszystkie te \u003Cstrong\u003Efajerwerki\u003C\/strong\u003E i \u015bwiecide\u0142ka, dzi\u0119ki kt\u00f3rym strona jest dynamiczniejsza i atrakcyjniejsza.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003ENajlepiej, gdyby warstwy te w og\u00f3le si\u0119 ze sob\u0105 nie miesza\u0142y. Dzi\u0119ki temu kod jest czystszy, a warstwy mog\u0105 by\u0107 u\u017cywane i modyfikowane niezale\u017cnie od siebie. Mo\u017cna na przyk\u0142ad w banalnie prosty spos\u00f3b zaimplementowa\u0107 r\u00f3\u017cne sk\u00f3rki na stronie, po prostu podmieniaj\u0105c u\u017cywany akrusz styl\u00f3w na inny. Je\u015bli w HTML-u nie umie\u015bcimy \u017cadnych styl\u00f3w inline (mam nadziej\u0119, \u017ce nikomu cho\u0107 troch\u0119 znaj\u0105cemu temat nie trzeba t\u0142umaczy\u0107, jak z\u0142y jest to pomys\u0142), lecz tylko dane oraz struktur\u0119, w jakiej s\u0105 u\u0142o\u017cone, to ca\u0142kowita zmiana wygl\u0105du strony jest nadzwyczaj \u0142atwa. (Dla przyk\u0142adu cho\u0107by \u003Ca href=\u0022http:\/\/bootswatch.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E bootswatch.com\u003C\/a\u003E albo \u003Ca href=\u0022http:\/\/www.csszengarden.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E csszengarden.com\u003C\/a\u003E \u2013 wszystkie podstrony w dziale \u201cthemes\u201d r\u00f3\u017cni\u0105 si\u0119 tylko jedn\u0105 rzecz\u0105: nazw\u0105 pliku .css)\u003C\/p\u003E\n\u003Cp\u003EDok\u0142adnie to samo tyczy si\u0119 JavaScriptu. Je\u015bli kod wykonywalny umie\u015bcimy bezpo\u015brednio wewn\u0105trz znacznika HTML, nasz kod staje si\u0119 zdecydowanie mniej czytelny i bardziej nara\u017cony na powtarzalno\u015b\u0107. Wprowadzanie w nim potem zmian mo\u017ce si\u0119 okaza\u0107 drog\u0105 przez m\u0119k\u0119. Powiedzmy, \u017ce po jakim\u015b czasie zechcemy zmieni\u0107 to brzydkie okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E na przyk\u0142ad na bootstrapowy \u003Ca href=\u0022http:\/\/getbootstrap.com\/javascript\/#modals\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E modal\u003C\/a\u003E. B\u0119dziemy wtedy musieli znale\u017a\u0107 wszystkie u\u017cycia podobnego kodu w naszym projekcie i przerobi\u0107 ka\u017cde z nich. Po co si\u0119 tak m\u0119czy\u0107?\u003C\/p\u003E\n\u003Cp\u003ENatkn\u0105\u0142em si\u0119 ostatnio na taki oto kod, maj\u0105cy wykona\u0107 nasze proste zadanie bez mieszania ze sob\u0105 warstw aplikacji:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;a class=\u0022js-delete-event\u0022 \n    href=\u0022javascript:void(0)\u0022\n    data-delete-url=\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\n    data-confirm-message=\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u0026gt;\n    {{ \u0027delete\u0027|l }}\n\u0026lt;\/a\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ENatomiast w pliku JavaScriptu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E$(\u0027.js-delete-event\u0027).on(\u0027click\u0027, function() {\n    if (true == confirm($(this).data(\u0027confirm-message\u0027))) {\n        window.location.href = $(this).data(\u0027delete-url\u0027);\n    }\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWygl\u0105da na zdecydowanie bardziej skomplikowany ni\u017c powien by\u0107... Niby jest w porz\u0105dku: w HTML-u nie mamy skrypt\u00f3w, a jedno z drugim komunikuje si\u0119 za pomoc\u0105 klas i atrybut\u00f3w \u003Ccode\u003Edata\u003C\/code\u003E, tak jak powinno by\u0107. HTML definiuje, \u017ce link jest klasy \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E, dok\u0105d powinien kierowa\u0107 i jak brzmi przet\u0142umaczona pro\u015bba o potwierdzenie, natomiast JS szuka wszystkich element\u00f3w z klas\u0105 \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E i podpina pod nie listenera, kt\u00f3ry o potwierdzenie faktycznie spyta, i w zale\u017cno\u015bci od odpowiedzi, przekierowuje u\u017cytkownika do strony usuwaj\u0105cej, b\u0105d\u017a te\u017c nie.\u003C\/p\u003E\n\u003Cp\u003EA jednak JS w tym HTML-owym kodzie si\u0119 pojawia, i to w swojej najbrzydszej formie: jako pseudoprotok\u00f3\u0142. Link, zamiast kierowa\u0107 nas do rzeczywistej strony, odsy\u0142a nas do jakiego\u015b \u003Ccode\u003Evoid(0)\u003C\/code\u003E przez nieistniej\u0105cy protok\u00f3\u0142 \u003Ccode\u003Ejavascript\u003C\/code\u003E... Jest to zwyk\u0142y zabieg maj\u0105cy na celu zablokowanie linka, skierowanie go donik\u0105d, ale jak\u017ce strasznie psuje semantyk\u0119 strony...\u003C\/p\u003E\n\u003Cp\u003EI ma w dupie \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Progressive_enhancement\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Progressive enhancement\u003C\/a\u003E. A to bardzo \u017ale, mie\u0107 go w dupie...\u003C\/p\u003E\n\u003Cp\u003EW progressive enhancement chodzi mniej wi\u0119cej o to, aby zapewni\u0107 dost\u0119p do wszystkich podstawowych danych na stronie oraz do wszystkich podstawowych funkcji naszej aplikacji dla \u003Cstrong\u003Eka\u017cdego\u003C\/strong\u003E u\u017cytkownika. Nawet je\u015bli u\u017cywa IE6 albo nie daj bogini jakiego\u015b lynxa czy innej wy\u0142\u0105cznie tekstowej przegl\u0105darki. Natomiast im jego przegl\u0105darka jest lepsza, nowocze\u015bniejsza i zgodniejsza ze standardami, tym wi\u0119cej deweloper mo\u017ce zaszale\u0107 z \u0142adnym wygl\u0105dem i wodotryskami.\u003C\/p\u003E\n\u003Cp\u003ENie zawsze u\u017cytkownikowi zadzia\u0142aj\u0105 skrypty. Mo\u017ce CDN z jak\u0105\u015b bibliotek\u0105 zaszwankuje, mo\u017ce user jedzie poci\u0105giem i mu net przerywa, a mo\u017ce po prostu sam je wy\u0142\u0105czy\u0142 (tak, niekt\u00f3rzy to robi\u0105).\u003C\/p\u003E\n\u003Cp\u003EJak w takim przypadku zadzia\u0142a powy\u017cszy kod? Ano w\u0142a\u015bnie, nie zadzia\u0142a w og\u00f3le. Chyba \u017ce user zajrzy w \u017ar\u00f3d\u0142o strony, domy\u015bli si\u0119, o co chodzi, i r\u0119cznie przejdzie do URL-a podanego w atrybucie \u003Ccode\u003Edata-delete-url\u003C\/code\u003E. Powodzenia.\u003C\/p\u003E\n\u003Cp\u003EA wi\u0119c progressive enhancement le\u017cy. Dla pewnej grupy u\u017cytkownik\u00f3w dost\u0119p do wa\u017cnej funkcjonalno\u015bci jest niemo\u017cliwy.\u003C\/p\u003E\n\u003Cp\u003ESp\u00f3jrzmy teraz na inny kod:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;a href=\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022 \n    data-confirm=\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u0026gt;\n    {{ \u0027delete\u0027|l }}\n\u0026lt;\/a\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cpre\u003E\u003Ccode\u003E$(\u0027a[data-confirm]\u0027).click(function() {\n    return confirm($(this).data(\u0027confirm\u0027));\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETutaj mamy w HTML-u najzwyczajniejszy w \u015bwiecie link, po prostu z jednym dodatkowym atrybutem. Gdyby z jakiego\u015b powodu nie za\u0142adowa\u0142 si\u0119 skypt, \u015bwiat si\u0119 nie zawali. U\u017cytkownik dalej ma mo\u017cliwo\u015b\u0107 usuni\u0119cia elementu, po prostu jest bardziej nara\u017cony na zrobienie tego przez przypadek, bo nie zobaczy potwierdzenia.\u003C\/p\u003E\n\u003Cp\u003EJe\u015bli natomiast JS dzia\u0142a, skrypt znajdzie wszystkie elementy posiadaj\u0105ce atrybut \u003Ccode\u003Edata-confirm\u003C\/code\u003E i podepnie pod nie listenera, zadaj\u0105cego u\u017cytkownikowi pytanie, kt\u00f3re si\u0119 w tym atrybucie znajduje.\u003C\/p\u003E\n\u003Cp\u003ETen kod jest o wiele lepszy od poprzedniego nie tylko ze wzgl\u0119du na respektowanie progressive enhancement:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EElement A zosta\u0142 odchudzony ze wszystkich zb\u0119dnych atrybut\u00f3w (czyli po\u0142owy!). W poprzednim kodzie jego autor uda\u0142, \u017ce link donik\u0105d nie kieruje, tylko po to, by p\u00f3\u017aniej przekaza\u0107 odpowiedni URL w osbobnym atrybucie. U\u017cy\u0142 te\u017c specjalnej klasy, po kt\u00f3rej JS mia\u0142 rozpozna\u0107 interesuj\u0105ce go elementy, mimo \u017ce sam fakt posiadania tekstu potwierdzenia ju\u017c dostatecznie jasno identyfikuje elementy, kt\u00f3re powinny wy\u015bwietli\u0107 potwierdzenie.\u003C\/li\u003E\n\u003Cli\u003EWykorzystanli\u015bmy \u015bwietnego ficzera jQuery \u2013 to, \u017ce zwr\u00f3cenie \u003Ccode\u003Efalse\u003C\/code\u003E w event hadlerze automatycznie zatrzymuje propagacj\u0119 zdarzenia. W bardzo elegancki i zwi\u0119z\u0142y spos\u00f3b zatrzymali\u015bmy przekierowanie po klikni\u0119ciu, bez potrzeby uciekania si\u0119 do pseudoprotoko\u0142\u00f3w ani \u003Ccode\u003Eevent.stoppropagation(); event.preventdefault();\u003C\/code\u003E, przy okazji jeszcze pytaj\u0105c o zgod\u0119 u\u017cytkownika \u2013 w jednej prostej linijce!\u003C\/li\u003E\n\u003Cli\u003ENie u\u017cywamy okropnego \u003Ccode\u003Ewindow.location.href\u003C\/code\u003E. Pozwalamy na zwyczajn\u0105 obs\u0142ug\u0119 operacji przekierowania po klikni\u0119ciu w link, po prostu rozszerzaj\u0105c j\u0105 o mo\u017cliwo\u015b\u0107 warunkowego przerwania, zamiast sztucznie i nieelegancko blokowa\u0107 przekierowanie tylko po to, by potem jeszcze sztuczniej wywo\u0142a\u0107 je od nowa...\u003C\/li\u003E\n\u003C\/ul\u003E","words":1140,"readTime":5,"lang":"pl"}}},"blog\/technology\/php-aspectmock-fa\u0142szowanie-czasu":{"key":"blog\/technology\/php-aspectmock-fa\u0142szowanie-czasu","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:40+02:00","publishedAt":"2015-07-30T09:25:00+02:00","group":"mocks","category":"blog","subcategory":"technology","slug":"php-aspectmock-fa\u0142szowanie-czasu"},"content":{"pl":{"slug":"php-aspectmock-fa\u0142szowanie-czasu","title":"PHP + AspectMock \u2013 fa\u0142szowanie czasu","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/php-aspectmock-fa\u0142szowanie-czasu_small.jpeg\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022291.32075471698\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAVCAYAAAAuJkyQAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGw0lEQVRIic2Wy45kRxGGv8jMc6s6dev73DxjM5ZBBgkhIbAsC5Y8Fk\/FIyB5hWBjyx7beKZ7erqnq7su534yM1jUvAEsiH1Iv\/6IL+IXQPk\/KpdYhw8B6yxpkoIaxAgigggoiqCAIAhRQFAEi2oEFBEBBFRRAYNBAdWICIhw6I9KFEUVRAVEMSKItUBk7AfcMit46GqmecGTk1PmQ0s+LYkacRjqcaCdLCiGlqWziEQqD8NyhSiY4Jk93DJdHBFiZO0D9vgEo5HolWJzyzQriAG8RqqjY+Lde05dggI7Y8kfP0Fix7t3VxgVxYghhkAzdFR1D80D435D4XcsGQm+x8fIi2RPX+\/5OB+IwdNcX7HYvOU477mQW1z9Dt3f86vqFXr7lt9+MufYRZ4Pa769fM1YrVH1ZGPNWb\/mm+tL0maLH0ZMkpO6FBNi\/GA5VPua0FV8VozMQ8unhefXZU1dNZxKx1hV3N7cs3u4x6iFpmbJHtO2vLmtOEkDj01Dv69p+5Hb6x3PJLLZN4xtw4WJ\/PH357y0I5t9zVBVPE4CUSO+6xmHHhdVESBxjtw5vriYsvOe81nCq03HdlTIhWlmuX6IDEa48w4xiiQTsqzldSV8tjJc14AVHqKlSwpe3+84SzLSPCedwJtguP9uwy\/yCW82I8VkypvR4tWTmuSwv6vJRLvRk2U5F48e4axBfEASizEOjMEmDosBDP1Qs1yt6AcljCNp7jCA9540z7m+umK1XJDnU7bbLcdHpwxjTz4piRpw1jKOAY0BMYIVgyikNnJ78xaHQlQlSRLKyQxrDRoi1hqisQe+RLBWIEb8mLDdVgjgQ2AYhBgVJ4a2HZjkE8ZupGs3RInsdvcA9H2LNe4DtYKooubAb55kJKmiUXHNOOJjZDad4TcbynKCOksaA2Fo6b0SFwuy+zVZWTALPY1N0OmcqIprKqZJxCUZMQw0OGK5OIjfPXDhBygmhBCpdxvqxYqyqpjM5kQ\/sI2R8uiEodkTQ8T1PmCNIfiRne+RuUcHh7UGEWj7nqxP6GdKOvfstx3GwbQI7Ko92teEJynN\/XvKk4LdemCyLJhdNyyKhHc09GZPt+7J84zMGKpTofJb7NyiQ46xjnGsUVEMH0YSYqT8\/BQ+WTD9wznfXF4xPM354fYGgNukpn7pyf5SULuartnz49Ur+s8j3RcZ4U85w5cp7qucG3dJPLKk5wuql8L9ccv32xv0dzmzTwte2wdujmt+Mvf4J2AQQlQUcxB0OKVKsUhYnc7IEotzDrrA0IxYk\/D4y1Pe\/P2G\/Cjl7IsLJEmRRIj7yI9\/uyK1GU7h56\/fcvJ8zsPlhvXllunJBHFgjUHriI97zn9zxObnisWzKXf\/3KAaiUER6xAwmmcZZ6slRVkimSWOHqMOYywalfl8Sqc9BMUbJfSRIsloupYQI6IQ8WSzCbGPiI1M3JxyWhAN+MET\/EjiUlQVSQwaI9EoGSllOePh5g1N3+MAVqsj8mLKJC+x1hIkYKwlzVJi9ABMzBRjDf04MNpAnhWsFitCGBmD8nC\/RrrI0WIOCE1VY01BIgl5liKFQQU0xIMTqhhr8MEz9iNt1SAWHChN23C0WCJDj6KkenilcaiILgURDBCx5NbgsgSItF2Ljh2zEJlmOYjSGUeMkVlZ0lUV0yFgrCAmoZGIphlpWyNiiAJ+MmO5PCaqYjEHh4a+xYllpiPLskAx6BjwfUc1yRmCZ1ZvyPOSpm7ZTpdY4iG39CPWGoyFEDx+6BFVpgjqPVaVEAURf3BFDLYfsVlO7Fp8NiFGTzGdMA7jYamjKtv9hlm553hV8dGLgX+8\/YmPXni+\/enfoJ7584ifPvD97SVdu2f38J7u9hVPTmqePW9xxR2nZxXzeEm4\/5mnzyZIblm92CPFmm9ff8fzT0rKGYT0jsnqjkef9jx9DF3X0PUdyAfKVBVVpakDPgpf\/2vNzX3LD+8GRt\/x+NwRhxFrAn\/+6hwjhjJLWC5S3r7Z4YwwSS3TSUpbR375csn9ZUseYHM3EBQmuaPdbDjNe55eZITR8\/66ZbuNDEPPtCwxzmJB\/mqMYbVY8nSVsO89F6uMd5UyRpBkSjEtMUZ4+74HcWyblKjKvvZU3nJ1NzIMsGsCKo51FbhqA41JeXQ+5f1aISl5aCzbGk7Olly+E86eHnNzD30\/MnQN9oA9aq3l2aMnGGuIAD5inCGqkqYpqLDbbxErnByf0LQ9282G1XJJVhSs12suzs4JYSSEQ4IMwRNipK5rFvMZziUYsYx+JE1TQvAgMPQDfhzAe4ZhOAj6H8fi\/6r+A3A83c4qjf3rAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/php-aspectmock-fa\u0142szowanie-czasu_small.jpeg\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022291.32075471698\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EW pewnym projekcie operuj\u0119 poprzez API na li\u015bcie wyda\u0144 produktu: zamykam wydania, kt\u00f3rych czas ju\u017c min\u0105\u0142, i tworz\u0119 nowe na osiem tygodni naprz\u00f3d. Moimi punktami odniesienia w czasie s\u0105:\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/php-aspectmock-fa\u0142szowanie-czasu_big.jpeg\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022636\u0022 height=\u0022386\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAVCAYAAAAuJkyQAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGw0lEQVRIic2Wy45kRxGGv8jMc6s6dev73DxjM5ZBBgkhIbAsC5Y8Fk\/FIyB5hWBjyx7beKZ7erqnq7su534yM1jUvAEsiH1Iv\/6IL+IXQPk\/KpdYhw8B6yxpkoIaxAgigggoiqCAIAhRQFAEi2oEFBEBBFRRAYNBAdWICIhw6I9KFEUVRAVEMSKItUBk7AfcMit46GqmecGTk1PmQ0s+LYkacRjqcaCdLCiGlqWziEQqD8NyhSiY4Jk93DJdHBFiZO0D9vgEo5HolWJzyzQriAG8RqqjY+Lde05dggI7Y8kfP0Fix7t3VxgVxYghhkAzdFR1D80D435D4XcsGQm+x8fIi2RPX+\/5OB+IwdNcX7HYvOU477mQW1z9Dt3f86vqFXr7lt9+MufYRZ4Pa769fM1YrVH1ZGPNWb\/mm+tL0maLH0ZMkpO6FBNi\/GA5VPua0FV8VozMQ8unhefXZU1dNZxKx1hV3N7cs3u4x6iFpmbJHtO2vLmtOEkDj01Dv69p+5Hb6x3PJLLZN4xtw4WJ\/PH357y0I5t9zVBVPE4CUSO+6xmHHhdVESBxjtw5vriYsvOe81nCq03HdlTIhWlmuX6IDEa48w4xiiQTsqzldSV8tjJc14AVHqKlSwpe3+84SzLSPCedwJtguP9uwy\/yCW82I8VkypvR4tWTmuSwv6vJRLvRk2U5F48e4axBfEASizEOjMEmDosBDP1Qs1yt6AcljCNp7jCA9540z7m+umK1XJDnU7bbLcdHpwxjTz4piRpw1jKOAY0BMYIVgyikNnJ78xaHQlQlSRLKyQxrDRoi1hqisQe+RLBWIEb8mLDdVgjgQ2AYhBgVJ4a2HZjkE8ZupGs3RInsdvcA9H2LNe4DtYKooubAb55kJKmiUXHNOOJjZDad4TcbynKCOksaA2Fo6b0SFwuy+zVZWTALPY1N0OmcqIprKqZJxCUZMQw0OGK5OIjfPXDhBygmhBCpdxvqxYqyqpjM5kQ\/sI2R8uiEodkTQ8T1PmCNIfiRne+RuUcHh7UGEWj7nqxP6GdKOvfstx3GwbQI7Ko92teEJynN\/XvKk4LdemCyLJhdNyyKhHc09GZPt+7J84zMGKpTofJb7NyiQ46xjnGsUVEMH0YSYqT8\/BQ+WTD9wznfXF4xPM354fYGgNukpn7pyf5SULuartnz49Ur+s8j3RcZ4U85w5cp7qucG3dJPLKk5wuql8L9ccv32xv0dzmzTwte2wdujmt+Mvf4J2AQQlQUcxB0OKVKsUhYnc7IEotzDrrA0IxYk\/D4y1Pe\/P2G\/Cjl7IsLJEmRRIj7yI9\/uyK1GU7h56\/fcvJ8zsPlhvXllunJBHFgjUHriI97zn9zxObnisWzKXf\/3KAaiUER6xAwmmcZZ6slRVkimSWOHqMOYywalfl8Sqc9BMUbJfSRIsloupYQI6IQ8WSzCbGPiI1M3JxyWhAN+MET\/EjiUlQVSQwaI9EoGSllOePh5g1N3+MAVqsj8mLKJC+x1hIkYKwlzVJi9ABMzBRjDf04MNpAnhWsFitCGBmD8nC\/RrrI0WIOCE1VY01BIgl5liKFQQU0xIMTqhhr8MEz9iNt1SAWHChN23C0WCJDj6KkenilcaiILgURDBCx5NbgsgSItF2Ljh2zEJlmOYjSGUeMkVlZ0lUV0yFgrCAmoZGIphlpWyNiiAJ+MmO5PCaqYjEHh4a+xYllpiPLskAx6BjwfUc1yRmCZ1ZvyPOSpm7ZTpdY4iG39CPWGoyFEDx+6BFVpgjqPVaVEAURf3BFDLYfsVlO7Fp8NiFGTzGdMA7jYamjKtv9hlm553hV8dGLgX+8\/YmPXni+\/enfoJ7584ifPvD97SVdu2f38J7u9hVPTmqePW9xxR2nZxXzeEm4\/5mnzyZIblm92CPFmm9ff8fzT0rKGYT0jsnqjkef9jx9DF3X0PUdyAfKVBVVpakDPgpf\/2vNzX3LD+8GRt\/x+NwRhxFrAn\/+6hwjhjJLWC5S3r7Z4YwwSS3TSUpbR375csn9ZUseYHM3EBQmuaPdbDjNe55eZITR8\/66ZbuNDEPPtCwxzmJB\/mqMYbVY8nSVsO89F6uMd5UyRpBkSjEtMUZ4+74HcWyblKjKvvZU3nJ1NzIMsGsCKo51FbhqA41JeXQ+5f1aISl5aCzbGk7Olly+E86eHnNzD30\/MnQN9oA9aq3l2aMnGGuIAD5inCGqkqYpqLDbbxErnByf0LQ9282G1XJJVhSs12suzs4JYSSEQ4IMwRNipK5rFvMZziUYsYx+JE1TQvAgMPQDfhzAe4ZhOAj6H8fi\/6r+A3A83c4qjf3rAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/php-aspectmock-fa\u0142szowanie-czasu_big.jpeg\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022636\u0022 height=\u0022386\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EW pewnym projekcie operuj\u0119 poprzez API na li\u015bcie wyda\u0144 produktu: zamykam wydania, kt\u00f3rych czas ju\u017c min\u0105\u0142, i tworz\u0119 nowe na osiem tygodni naprz\u00f3d. Moimi punktami odniesienia w czasie s\u0105:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003Enew \\DateTime\u003C\/code\u003E \u2013 dzi\u015b,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003Enew \\DateTime(\u0027+8 weeks\u0027)\u003C\/code\u003E \u2013 koniec okresu, w kt\u00f3rym tworz\u0119 wydania,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003Enew \\DateTime(\u0027last friday\u0027)\u003C\/code\u003E \u2013 bo cykl ka\u017cdego wydania ko\u0144czy si\u0119 w pi\u0105tek, od tej daty iteruj\u0119 \u003Ccode\u003E+1 week\u003C\/code\u003E tworz\u0105c nowe wydania.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EDwie sprawy komplikuj\u0105 nam \u017cycie, je\u015bli chcemy stworzy\u0107 testy jednostkowe do tej klasy: po pierwsze nie powinni\u015bmy \u003Cem\u003Enaprawd\u0119\u003C\/em\u003E odwo\u0142ywa\u0107 si\u0119 do API, a jedynie uda\u0107 zapytania, a po drugie powinni\u015bmy uda\u0107 \u017ce \u003Cem\u003Edzisiaj\u003C\/em\u003E jest kt\u00f3ry\u015btam, jaka\u015b sta\u0142a data, do kt\u00f3rej b\u0119d\u0105 dostosowane nasze przypadki testowe.\u003C\/p\u003E\n\u003Cp\u003EMusimy zatem stworzy\u0107 par\u0119 dubli \u2013 klas, kt\u00f3re \u201cprzys\u0142oni\u0105\u201d swoje pierwowzory, podmieniaj\u0105c niekt\u00f3re ich metody na swoje. \u015awietnym narz\u0119dziem do tego celu jest biblioteka \u003Ca href=\u0022https:\/\/github.com\/Codeception\/AspectMock\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E AspectMock\u003C\/a\u003E, potrafi\u0105ca stworzy\u0107 takie duble, kt\u00f3re wszystkim innym nawet si\u0119 nie \u015bni\u0142y (np. duble metod statycznych czy funkcji systemowych).\u003C\/p\u003E\n\u003Cp\u003ENiestety, cho\u0107 AspectMock potrafi \u201cnadpisa\u0107\u201d funkcj\u0119 \u003Ccode\u003Etime()\u003C\/code\u003E, na nic to si\u0119 zda, je\u015bli u\u017cywamy \u003Ccode\u003EDateTime\u003C\/code\u003E (a kto nie u\u017cywa?), a j\u0105 nadpisa\u0107 jest ju\u017c ci\u0119\u017cej. Na szcz\u0119\u015bcie da si\u0119 to zrobi\u0107 za pomoc\u0105 pewnej sztuczki:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-meta\u0022\u003E\u0026lt;?php\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Enamespace\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EVR\u003C\/span\u003E\\\u003Cspan class=\u0022hljs-title\u0022\u003ERedmine\u003C\/span\u003E;\n\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EVersionsHandler\u003C\/span\u003E\n\u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-comment\u0022\u003E\/** \u003Cspan class=\u0022hljs-doctag\u0022\u003E@var\u003C\/span\u003E Api *\/\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E $api;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E $now;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E $until;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003E__construct\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E(Api $api)\u003C\/span\u003E\n    \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;api = $api;\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;now = TimeProvider::getDateTimeFormatted();\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;until = TimeProvider::getDateTimeFormatted(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027+8 weeks\u0027\u003C\/span\u003E);\n    }\n\n    \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ (...)\u003C\/span\u003E\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EgetToBeCreated\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E\n    \u003C\/span\u003E{\n        $current = TimeProvider::getDateTime(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027last friday\u0027\u003C\/span\u003E);\n        \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ (...)\u003C\/span\u003E\n    }\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EJak wida\u0107, we wszystkich miejscach, gdzie normalnie u\u017cy\u0142bym \u003Ccode\u003EDateTime\u003C\/code\u003E, ja korzystam z klasy \u003Ccode\u003ETimeProvider\u003C\/code\u003E. Jest ona bardzo pro\u015bciutka:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-meta\u0022\u003E\u0026lt;?php\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Enamespace\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EVR\u003C\/span\u003E\\\u003Cspan class=\u0022hljs-title\u0022\u003ERedmine\u003C\/span\u003E;\n\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003ETimeProvider\u003C\/span\u003E\n\u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Estatic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EgetDateTime\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($time = \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027now\u0027\u003C\/span\u003E)\u003C\/span\u003E\n    \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E \\DateTime($time);\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Estatic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EgetDateTimeFormatted\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($time = \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027now\u0027\u003C\/span\u003E)\u003C\/span\u003E\n    \u003C\/span\u003E{\n        $datetime = \u003Cspan class=\u0022hljs-keyword\u0022\u003Eself\u003C\/span\u003E::getDateTime($time);\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $datetime-\u0026gt;format(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027Y.\\WW\u0027\u003C\/span\u003E);\n    }\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EI istnieje tylko po to, by m\u00f3c j\u0105 zdublowa\u0107 w nast\u0119puj\u0105cy spos\u00f3b:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E$timeProxy = Test::double(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027VR\\\\Redmine\\\\TimeProvider\u0027\u003C\/span\u003E, [\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027getDateTime\u0027\u003C\/span\u003E =\u0026gt; \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($time)\u003C\/span\u003E \u003C\/span\u003E{\n    $dt = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E \\DateTime(\u003Cspan class=\u0022hljs-string\u0022\u003E\u00272015-01-14\u0027\u003C\/span\u003E);\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $dt-\u0026gt;modify($time);\n}]);\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EA zatem podczas normalnego uruchomienia aplikacji, \u003Ccode\u003ETimeProvider\u003C\/code\u003E dzia\u0142a po prostu jak nicnierobi\u0105ca fabryka \u003Ccode\u003EDateTime\u003C\/code\u003E\u2019\u00f3w. W czasie test\u00f3w jednak obiera ona za punkt odniesienia arbitraln\u0105 dat\u0119 \u003Ccode\u003E2015-01-04\u003C\/code\u003E, a potem modyfikuje j\u0105 o to, co podamy jej w parametrze, jak jakby dzi\u015b by\u0142 \u003Ccode\u003E2015-01-04\u003C\/code\u003E. Zawsze, niezale\u017cnie kiedy uruchomimy test.\u003C\/p\u003E\n\u003Cp\u003ETeraz wystarczy tylko zdublowa\u0107 funkcj\u0119 odwo\u0142uj\u0105c\u0105 si\u0119 do API i przeprowadzi\u0107 testy:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E$apiProxy = Test::double(\n  \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027VR\\\\Redmine\\\\Api\u0027\u003C\/span\u003E,\n  [\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027curl\u0027\u003C\/span\u003E =\u0026gt; \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($url, $method = \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027GET\u0027\u003C\/span\u003E, $data = [])\u003C\/span\u003E \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E ($method != \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027GET\u0027\u003C\/span\u003E) { \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Enull\u003C\/span\u003E; }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E json_encode(\u003Cspan class=\u0022hljs-comment\u0022\u003E\/* mocked api response *\/\u003C\/span\u003E);\n}]);\n\n$handler = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E VersionsHandler(\u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E Api);\n\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;assertEquals(\u003Cspan class=\u0022hljs-comment\u0022\u003E\/* expected output *\/\u003C\/span\u003E, $handler-\u0026gt;handle());\n\u003C\/code\u003E\u003C\/pre\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["aop","aspectmock","czas","datetime","php","programowanie"],"hasMore":true,"image":"https:\/\/avris.it\/image\/php-aspectmock-fa\u0142szowanie-czasu_small.jpeg","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/php-aspectmock-fa\u0142szowanie-czasu_big.jpeg\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/php-aspectmock-fa\u0142szowanie-czasu_mini.jpeg\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022145.66037735849\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EW pewnym projekcie operuj\u0119 poprzez API na li\u015bcie wyda\u0144 produktu: zamykam wydania, kt\u00f3rych czas ju\u017c min\u0105\u0142, i tworz\u0119 nowe na osiem tygodni naprz\u00f3d. Moimi punktami odniesienia w czasie s\u0105:\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/php-aspectmock-fa\u0142szowanie-czasu_big.jpeg\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/php-aspectmock-fa\u0142szowanie-czasu_mini.jpeg\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022145.66037735849\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EW pewnym projekcie operuj\u0119 poprzez API na li\u015bcie wyda\u0144 produktu: zamykam wydania, kt\u00f3rych czas ju\u017c min\u0105\u0142, i tworz\u0119 nowe na osiem tygodni naprz\u00f3d. Moimi punktami odniesienia w czasie s\u0105:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003Enew \\DateTime\u003C\/code\u003E \u2013 dzi\u015b,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003Enew \\DateTime(\u0027+8 weeks\u0027)\u003C\/code\u003E \u2013 koniec okresu, w kt\u00f3rym tworz\u0119 wydania,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003Enew \\DateTime(\u0027last friday\u0027)\u003C\/code\u003E \u2013 bo cykl ka\u017cdego wydania ko\u0144czy si\u0119 w pi\u0105tek, od tej daty iteruj\u0119 \u003Ccode\u003E+1 week\u003C\/code\u003E tworz\u0105c nowe wydania.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EDwie sprawy komplikuj\u0105 nam \u017cycie, je\u015bli chcemy stworzy\u0107 testy jednostkowe do tej klasy: po pierwsze nie powinni\u015bmy \u003Cem\u003Enaprawd\u0119\u003C\/em\u003E odwo\u0142ywa\u0107 si\u0119 do API, a jedynie uda\u0107 zapytania, a po drugie powinni\u015bmy uda\u0107 \u017ce \u003Cem\u003Edzisiaj\u003C\/em\u003E jest kt\u00f3ry\u015btam, jaka\u015b sta\u0142a data, do kt\u00f3rej b\u0119d\u0105 dostosowane nasze przypadki testowe.\u003C\/p\u003E\n\u003Cp\u003EMusimy zatem stworzy\u0107 par\u0119 dubli \u2013 klas, kt\u00f3re \u201cprzys\u0142oni\u0105\u201d swoje pierwowzory, podmieniaj\u0105c niekt\u00f3re ich metody na swoje. \u015awietnym narz\u0119dziem do tego celu jest biblioteka \u003Ca href=\u0022https:\/\/github.com\/Codeception\/AspectMock\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E AspectMock\u003C\/a\u003E, potrafi\u0105ca stworzy\u0107 takie duble, kt\u00f3re wszystkim innym nawet si\u0119 nie \u015bni\u0142y (np. duble metod statycznych czy funkcji systemowych).\u003C\/p\u003E\n\u003Cp\u003ENiestety, cho\u0107 AspectMock potrafi \u201cnadpisa\u0107\u201d funkcj\u0119 \u003Ccode\u003Etime()\u003C\/code\u003E, na nic to si\u0119 zda, je\u015bli u\u017cywamy \u003Ccode\u003EDateTime\u003C\/code\u003E (a kto nie u\u017cywa?), a j\u0105 nadpisa\u0107 jest ju\u017c ci\u0119\u017cej. Na szcz\u0119\u015bcie da si\u0119 to zrobi\u0107 za pomoc\u0105 pewnej sztuczki:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;?php\nnamespace VR\\Redmine;\n\nclass VersionsHandler\n{\n    \/** @var Api *\/\n    private $api;\n\n    private $now;\n\n    private $until;\n\n    public function __construct(Api $api)\n    {\n        $this-\u0026gt;api = $api;\n\n        $this-\u0026gt;now = TimeProvider::getDateTimeFormatted();\n\n        $this-\u0026gt;until = TimeProvider::getDateTimeFormatted(\u0027+8 weeks\u0027);\n    }\n\n    \/\/ (...)\n\n    private function getToBeCreated()\n    {\n        $current = TimeProvider::getDateTime(\u0027last friday\u0027);\n        \/\/ (...)\n    }\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EJak wida\u0107, we wszystkich miejscach, gdzie normalnie u\u017cy\u0142bym \u003Ccode\u003EDateTime\u003C\/code\u003E, ja korzystam z klasy \u003Ccode\u003ETimeProvider\u003C\/code\u003E. Jest ona bardzo pro\u015bciutka:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;?php\nnamespace VR\\Redmine;\n\nclass TimeProvider\n{\n    public static function getDateTime($time = \u0027now\u0027)\n    {\n        return new \\DateTime($time);\n    }\n\n    public static function getDateTimeFormatted($time = \u0027now\u0027)\n    {\n        $datetime = self::getDateTime($time);\n\n        return $datetime-\u0026gt;format(\u0027Y.\\WW\u0027);\n    }\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EI istnieje tylko po to, by m\u00f3c j\u0105 zdublowa\u0107 w nast\u0119puj\u0105cy spos\u00f3b:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E$timeProxy = Test::double(\u0027VR\\\\Redmine\\\\TimeProvider\u0027, [\u0027getDateTime\u0027 =\u0026gt; function($time) {\n    $dt = new \\DateTime(\u00272015-01-14\u0027);\n    return $dt-\u0026gt;modify($time);\n}]);\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EA zatem podczas normalnego uruchomienia aplikacji, \u003Ccode\u003ETimeProvider\u003C\/code\u003E dzia\u0142a po prostu jak nicnierobi\u0105ca fabryka \u003Ccode\u003EDateTime\u003C\/code\u003E\u2019\u00f3w. W czasie test\u00f3w jednak obiera ona za punkt odniesienia arbitraln\u0105 dat\u0119 \u003Ccode\u003E2015-01-04\u003C\/code\u003E, a potem modyfikuje j\u0105 o to, co podamy jej w parametrze, jak jakby dzi\u015b by\u0142 \u003Ccode\u003E2015-01-04\u003C\/code\u003E. Zawsze, niezale\u017cnie kiedy uruchomimy test.\u003C\/p\u003E\n\u003Cp\u003ETeraz wystarczy tylko zdublowa\u0107 funkcj\u0119 odwo\u0142uj\u0105c\u0105 si\u0119 do API i przeprowadzi\u0107 testy:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E$apiProxy = Test::double(\n  \u0027VR\\\\Redmine\\\\Api\u0027,\n  [\u0027curl\u0027 =\u0026gt; function($url, $method = \u0027GET\u0027, $data = []) {\n    if ($method != \u0027GET\u0027) { return null; }\n\n    return json_encode(\/* mocked api response *\/);\n}]);\n\n$handler = new VersionsHandler(new Api);\n\n$this-\u0026gt;assertEquals(\/* expected output *\/, $handler-\u0026gt;handle());\u003C\/code\u003E\u003C\/pre\u003E","words":455,"readTime":2,"lang":"pl"}}},"blog\/technology\/frontendowa-magia-coffeescript-sass-scss-less":{"key":"blog\/technology\/frontendowa-magia-coffeescript-sass-scss-less","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:39+02:00","publishedAt":"2015-07-26T18:00:00+02:00","group":null,"category":"blog","subcategory":"technology","slug":"frontendowa-magia-coffeescript-sass-scss-less"},"content":{"pl":{"slug":"frontendowa-magia-coffeescript-sass-scss-less","title":"Frontendowa magia: CoffeeScript, Sass, Scss, Less...","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_small.jpeg\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022364.93358633776\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAbCAYAAAAULC3gAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEuUlEQVRIib2X228UVRzHP2dmdna6l962l+XSLaVeSiFRsoqAQf8A4jvvtn+CzxhjMDHEEJ8MATG+mfiAzz4QTYCk4UExpqlgAxTa0la67exlZs6Zc3woW7f2tqvQbzKZ35mcM9\/f\/M739zu\/EWYNCCEAeNF24x3Y1XbqgzqasVtBfV2zHEJrbf4T0\/9EHMfYtr3pubUX5I1RmJmZ4fz5j7l27ZstI+XshUMAs7OzXLlyFSkl4+NjFAqFLecJU1fVS8Lc3BxXr36N75cZHx9jePjwjnp04MVnFkAQhFy\/\/gMTExOMjX3IkSMjwO5ZJnZK+0YYY4iiiLt37zI7OwcYOju7KBQGKBQK2LaNMQalFE+ezJNwXNLpBK7IYrcLXGEgjhBOeneHmgn9rVu3uXDhM0ql0iZH29raOHbsKMVikePH3ySVSjM0mAMrBWYZVbZY8Vbokg6iEiN6D227bU05pJTi7NkPKJfL68+klERRhDEGy7LWvzCOY3K5borFtzh9+hT9\/XkqlSqO7XDmVDtOIgdEiMQrW3I1nWWWZaG1BkBrTalUeu6QXp+TzXTQ6e0jWx1m9qcuFjs93jlxiGx7llSqjcjSPFA1hkyJ2oIi27eZ3mlmx2zb5uLFz7l06UsmJycRQtDb04sKLOywg5Q8QF\/yCKP73yVccZl\/sohlWaQqefYfyD8P6W\/UghKHvbexsMj0\/qNZaDg6Gs+b+oSt7NHRUS5f\/gqlFN99Osn33\/6IKttYsUfSypJO99A3fJggMkROBks4xKXnOtGr4Izgq18IHldJWR6dA1vX5JYKoxACx3F4FP9M3D2DlejAjjpxSZPJpsn1SGqpgIXgKWX3EU9H7qH0R6hVDy9zn1wiT2ZgGUT\/thybHNrtEDTGML8yTdw3jek1aNsmSCYptbcz90aRimXxV\/sd0rJGWBrCSIfrn\/zOuQuDlJNZMiIAvA3vbZSNVR8YYzZcWhvi2KCkRkYxUaSIIoXvV\/F9H8dx8DyPTDpJPpsi\/16ITC2TTdfYl1OcyXl4lWc48R3OfTGCuXmbvNE0Hp91rrq9ZYSUNIRhRBRJtNYNixQA0\/P3OJD3KZVsnESCXDeUqwZvKUk50iS7F1gopZnKr5B41oHiVRL6GeL9AbAkQng7FsYNyooVVKsB1WoNKSVKqbUrjpEKypFBrUimpta+I5N1kbEAI9jnS9yMICocxdiaP2faSNYqzC8\/xjcGnNeB5LbaWd+yDQN7LcUNawVOKbVWAMOQMAjQQY3FJR+tfQouHHutzGrJxvb7mZrzWFgKcVYWsJTg6KjDH0nwoxhLJP9NtS02pL0QkM64uK5NtRYS1AKiKEJrjZQRYRixtLRIqEC6gpsT4NiSnqEHtLkpDvqrTP+6xODBVe7dt6jVPGLfJm11NuUMNBTGRqUnXJsON0V7ewqtDTrWxDrGX\/VRShFrxcOqJpFIEAt4vAqOlswlKqQti1AKyhWDMWvb3YhGnq3slvshKRU3btxgYmKChw8fsby8TDZrcGybMEriukm6uroYHBzk5MkTFIvFDeu36yTWe+8X0VMHQUAcxziOQzK5u3B3wp40+a38Bu1Jk98KWnao8T+rGbtlh142Qav4G4sUzOeqTN6uAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_small.jpeg\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022364.93358633776\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022729.86717267552\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAbCAYAAAAULC3gAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEuUlEQVRIib2X228UVRzHP2dmdna6l962l+XSLaVeSiFRsoqAQf8A4jvvtn+CzxhjMDHEEJ8MATG+mfiAzz4QTYCk4UExpqlgAxTa0la67exlZs6Zc3woW7f2tqvQbzKZ35mcM9\/f\/M739zu\/EWYNCCEAeNF24x3Y1XbqgzqasVtBfV2zHEJrbf4T0\/9EHMfYtr3pubUX5I1RmJmZ4fz5j7l27ZstI+XshUMAs7OzXLlyFSkl4+NjFAqFLecJU1fVS8Lc3BxXr36N75cZHx9jePjwjnp04MVnFkAQhFy\/\/gMTExOMjX3IkSMjwO5ZJnZK+0YYY4iiiLt37zI7OwcYOju7KBQGKBQK2LaNMQalFE+ezJNwXNLpBK7IYrcLXGEgjhBOeneHmgn9rVu3uXDhM0ql0iZH29raOHbsKMVikePH3ySVSjM0mAMrBWYZVbZY8Vbokg6iEiN6D227bU05pJTi7NkPKJfL68+klERRhDEGy7LWvzCOY3K5borFtzh9+hT9\/XkqlSqO7XDmVDtOIgdEiMQrW3I1nWWWZaG1BkBrTalUeu6QXp+TzXTQ6e0jWx1m9qcuFjs93jlxiGx7llSqjcjSPFA1hkyJ2oIi27eZ3mlmx2zb5uLFz7l06UsmJycRQtDb04sKLOywg5Q8QF\/yCKP73yVccZl\/sohlWaQqefYfyD8P6W\/UghKHvbexsMj0\/qNZaDg6Gs+b+oSt7NHRUS5f\/gqlFN99Osn33\/6IKttYsUfSypJO99A3fJggMkROBks4xKXnOtGr4Izgq18IHldJWR6dA1vX5JYKoxACx3F4FP9M3D2DlejAjjpxSZPJpsn1SGqpgIXgKWX3EU9H7qH0R6hVDy9zn1wiT2ZgGUT\/thybHNrtEDTGML8yTdw3jek1aNsmSCYptbcz90aRimXxV\/sd0rJGWBrCSIfrn\/zOuQuDlJNZMiIAvA3vbZSNVR8YYzZcWhvi2KCkRkYxUaSIIoXvV\/F9H8dx8DyPTDpJPpsi\/16ITC2TTdfYl1OcyXl4lWc48R3OfTGCuXmbvNE0Hp91rrq9ZYSUNIRhRBRJtNYNixQA0\/P3OJD3KZVsnESCXDeUqwZvKUk50iS7F1gopZnKr5B41oHiVRL6GeL9AbAkQng7FsYNyooVVKsB1WoNKSVKqbUrjpEKypFBrUimpta+I5N1kbEAI9jnS9yMICocxdiaP2faSNYqzC8\/xjcGnNeB5LbaWd+yDQN7LcUNawVOKbVWAMOQMAjQQY3FJR+tfQouHHutzGrJxvb7mZrzWFgKcVYWsJTg6KjDH0nwoxhLJP9NtS02pL0QkM64uK5NtRYS1AKiKEJrjZQRYRixtLRIqEC6gpsT4NiSnqEHtLkpDvqrTP+6xODBVe7dt6jVPGLfJm11NuUMNBTGRqUnXJsON0V7ewqtDTrWxDrGX\/VRShFrxcOqJpFIEAt4vAqOlswlKqQti1AKyhWDMWvb3YhGnq3slvshKRU3btxgYmKChw8fsby8TDZrcGybMEriukm6uroYHBzk5MkTFIvFDeu36yTWe+8X0VMHQUAcxziOQzK5u3B3wp40+a38Bu1Jk98KWnao8T+rGbtlh142Qav4G4sUzOeqTN6uAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022729.86717267552\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E\n\u003Cp\u003EZ drugiej jednak strony t\u0119 sam\u0105 przeno\u015bno\u015b\u0107 mo\u017cna te\u017c uzna\u0107 za wad\u0119. Ca\u0142y Internet sprowadza si\u0119 bowiem ostatnio do tej \u015bwi\u0119tej tr\u00f3jcy: \u003Cstrong\u003EHTML5 + CSS3 + JS\u003C\/strong\u003E. Bo skoro te trzy potrafi\u0105 ju\u017c wszystko to, co kiedy\u015b umia\u0142y tylko \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/flash\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Flash\u003C\/a\u003E czy aplety \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/java\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Javy\u003C\/a\u003E, to po co ryzykowa\u0107 bezpiecze\u0144stwo witryny, zmusza\u0107 u\u017cytkownika do instalowania wtyczek i odbiera\u0107 sobie mo\u017cliwo\u015b\u0107 lepszej integracji element\u00f3w strony? Po prostu \u003Cem\u003Enie ma sensu\u003C\/em\u003E wychodzi\u0107 poza \u015bwi\u0119t\u0105 tr\u00f3jc\u0119. A jej rozw\u00f3j jest niestety ograniczony aktualizacjami przegl\u0105darek. Czy zatem jeste\u015bmy na ni\u0105 \u003Cstrong\u003Eskazani\u003C\/strong\u003E?\u003C\/p\u003E\n\u003Cp\u003ENa szcz\u0119\u015bcie nie! Istnieje ca\u0142a rodzina j\u0119zyk\u00f3w, kt\u00f3re bardzo sprytnie obchodz\u0105 ten problem. Wprowadzaj\u0105 ogromne ulepszenia i u\u0142atwienia, ale bez potrzeby interpretowania ich przez przegl\u0105darki! Po prostu po stronie programisty s\u0105 kompilowane do jednego z tych j\u0119zyk\u00f3w, kt\u00f3re ka\u017cda przegl\u0105darka rozumie.\u003C\/p\u003E\n\u003Cp\u003EPowiedzmy na przyk\u0142ad, \u017ce chcesz stworzy\u0107 w CSS klasy od \u003Ccode\u003Ecol-1\u003C\/code\u003E do \u003Ccode\u003Ecol-12\u003C\/code\u003E, z kt\u00f3rych ka\u017cda b\u0119dzie nadawa\u0142a DIV-owi szeroko\u015b\u0107 r\u00f3wn\u0105 ile\u015btam dwunastych szeroko\u015bci kontenera. W \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/thesassway.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Sass\u003C\/a\u003E\u003C\/strong\u003E zajmuje to trzy linijki:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs scss border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003E@for\u003C\/span\u003E \u003Cspan class=\u0022hljs-variable\u0022\u003E$i\u003C\/span\u003E from \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E through \u003Cspan class=\u0022hljs-number\u0022\u003E12\u003C\/span\u003E\n  .col-#{\u003Cspan class=\u0022hljs-variable\u0022\u003E$i\u003C\/span\u003E}\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-variable\u0022\u003E$i\u003C\/span\u003E\/\u003Cspan class=\u0022hljs-number\u0022\u003E12\u003C\/span\u003E * \u003Cspan class=\u0022hljs-number\u0022\u003E100%\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EA jest kompilowane do takiego kodu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs css border\u0022\u003E\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-1\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E8.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-2\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E16.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-3\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E25%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-4\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E33.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-5\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E41.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-6\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E50%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-7\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E58.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-8\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E66.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-9\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E75%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-10\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E83.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-11\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E91.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-12\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E100%\u003C\/span\u003E; }\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EPierwszy z nich jest prosty, kr\u00f3tki i czytelny dla cz\u0142owieka, drugi natomiast zostanie zrozumiany przez wszystkie przegl\u0105darki. I wilk syty i owca ca\u0142a! Sass zawiera wiele element\u00f3w, kt\u00f3rych prostemu CSS-owi brakuje: zmiennych, instrukcji warunkowych, p\u0119tli, funkcji (tzw. mixins), zagnie\u017cd\u017ce\u0144, operacji arytmetycznych... O ile bardziej \u003Cstrong\u003Eelastyczny\u003C\/strong\u003E staje si\u0119 kod, gdy mo\u017cemy zdefiniowa\u0107 na przyk\u0142ad zmienn\u0105 \u003Ccode\u003E$navWidth: 300px\u003C\/code\u003E i u\u017cy\u0107 jej w pi\u0119ciu innych miejscach (r\u00f3wnie\u017c w wyra\u017ceniach arytmetycznych, np. \u003Ccode\u003Ewidth: $navWidth \/ 2 + 16px\u003C\/code\u003E), zamiast wsz\u0119dzie podawa\u0107 j\u0105 wprost. Ka\u017cda zmiana szeroko\u015bci nawigacji jest wtedy po prostu \u003Cstrong\u003Ebanalna\u003C\/strong\u003E, nie wymaga szukania wszystkich zale\u017cno\u015bci. O ile \u003Cstrong\u003Ekr\u00f3tszy i bardziej przejrzysty\u003C\/strong\u003E staje si\u0119 kod, je\u015bli mo\u017cemy cz\u0119sto powtarzaj\u0105ce si\u0119 elementy zamkn\u0105\u0107 w parametryzowane mixiny i po prostu si\u0119 do nich odwo\u0142ywa\u0107? \u015awietn\u0105 list\u0119 sassowych ficzer\u00f3w mo\u017cna znale\u017a\u0107 cho\u0107by na \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Sass_(stylesheet_language)\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Wikipedii\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cp\u003EPodobnymi do niego j\u0119zykami s\u0105 \u003Cstrong\u003EScss\u003C\/strong\u003E oras \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/lesscss.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Less\u003C\/a\u003E\u003C\/strong\u003E. Wol\u0119 jednak Sassa z jednego powodu \u2013 \u003Cstrong\u003Ebrak klamer\u003C\/strong\u003E. Skoro i tak w ka\u017cdym kodzie powinno si\u0119 stosowa\u0107 odpowiednie wci\u0119cia tabulatorami, to klamry staj\u0105 si\u0119 zwyczajnie zb\u0119dne. J\u0119zyk, kt\u00f3ry wymusza stosowanie wci\u0119\u0107 w kodzie po pierwsze wymaga mniej klepania w klawiatur\u0119, a po drugie daje gwarancj\u0119, \u017ce po kim by\u015bmy kodu nie przej\u0119li, zawsze przynajmniej pod tym wzgl\u0119dem b\u0119dzie on czytelny. Same plusy! Z tego samego za\u0142o\u017cenia wyszli chocia\u017cby tw\u00f3rcy \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.ruby-lang.org\/pl\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Rubiego\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.python.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Pythona\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E CoffeeScriptu\u003C\/a\u003E\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Cp\u003EA no w\u0142a\u015bnie, \u003Cstrong\u003ECoffeeScript\u003C\/strong\u003E. \u017bywy dow\u00f3d, \u017ce nawet tworzenie JavaScript\u00f3w mo\u017ce by\u0107 przyjemne (s\u0142owo daj\u0119, nie uwierzy\u0142bym, gdybym nie spr\u00f3bowa\u0142). W JS to dopiero jest nadmiar nawias\u00f3w i klamer:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Esse = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E EventSource(Routing.generate(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_check\u0027\u003C\/span\u003E));\nsse.addEventListener(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Ee\u003C\/span\u003E) \u003C\/span\u003E{\n  \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (e.data == \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027test\u0027\u003C\/span\u003E || e.data == \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dev\u0027\u003C\/span\u003E) { \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E; }\n  $.post(Routing.generate(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_fetch\u0027\u003C\/span\u003E), { \u003Cspan class=\u0022hljs-attr\u0022\u003Eids\u003C\/span\u003E: e.data }, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Edata\u003C\/span\u003E) \u003C\/span\u003E{\n    conversation.html(data);\n  });\n}, \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E);\n\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETa sama funkcjonalno\u015b\u0107 w CoffeeScripcie wygl\u0105da nast\u0119puj\u0105co:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Esse = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E EventSource Routing.generate \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_check\u0027\u003C\/span\u003E\nsse.addEventListener \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation\u0027\u003C\/span\u003E, (e) -\u0026gt;\n  \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E e.data \u003Cspan class=\u0022hljs-keyword\u0022\u003Ein\u003C\/span\u003E [\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027test\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dev\u0027\u003C\/span\u003E]\n  $.post(Routing.generate(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_fetch\u0027\u003C\/span\u003E), { \u003Cspan class=\u0022hljs-attr\u0022\u003Eids\u003C\/span\u003E: e.data }, (data) -\u0026gt;\n    conversation.html(data)\n  )\n, \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWystarczy\u0142o zast\u0105pienie sk\u0142adni \u003Ccode\u003Efunction(a) {...}\u003C\/code\u003E prostym \u003Ccode\u003E(a) -\u0026gt; ...\u003C\/code\u003E, zmiana klamer na wci\u0119cia oraz mo\u017cliwo\u015b\u0107 pomini\u0119cia niekt\u00f3rych nawias\u00f3w w parametrach funkcji \u2013 i voil\u00e0! Mniej klepania w klawiatur\u0119 i doszukiwania si\u0119 par nawias\u00f3w, a tre\u015bci tyle samo!\u003C\/p\u003E\n\u003Cp\u003ENie spos\u00f3b si\u0119 nachwali\u0107 wszystkich ficzer\u00f3w CoffeeScriptu... JSON-owe obiekty mo\u017cna w nim definiowa\u0107 podobnie jak w \u003Ca href=\u0022http:\/\/yaml.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E YAML-u\u003C\/a\u003E, p\u0119tl\u0119 mo\u017cna od 1 do 100 zawrze\u0107 w kr\u00f3ciutkim zapisie \u003Ccode\u003E1..100\u003C\/code\u003E, zmiennych nie trzeba deklarowa\u0107, mo\u017cna im przypisywa\u0107 warto\u015bci do wielu na raz (a nawet zamienia\u0107 je warto\u015bciami w jednej linijce: \u003Ccode\u003E[foo, bar] = [bar, foo]\u003C\/code\u003E i tyle!). Najlepiej po prostu przejrze\u0107 jego \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E stron\u0119 domow\u0105\u003C\/a\u003E i milcze\u0107 w \u003Cstrong\u003Ezachwycie\u003C\/strong\u003E!\u003C\/p\u003E\n\u003Cp\u003ER\u00f3wnie\u017c w przypadku HTML-a istnieje wiele technologii, kt\u00f3re pozwalaj\u0105 na wygenerowanie go na postawie bardziej wyrafinowanych j\u0119zyk\u00f3w. Lecz tutaj to troch\u0119 co innego. Mowa o template engines takich jak \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/twig.sensiolabs.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Twig\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.smarty.net\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Smarty\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/haml.info\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Haml\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.stuartellis.eu\/articles\/erb\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Erb\u003C\/a\u003E\u003C\/strong\u003E \u2013 one jednak s\u0105 kompilowane do j\u0119zyk\u00f3w wykonywanych po stronie serwera (PHP, Ruby, Python...), wi\u0119c niezbyt pasuj\u0105 do mojego zestawienia. (Nota bene w Hamlu jeszcze bardziej zredukowana jest klamrowa redundancja: z \u003Ccode\u003E\u0026lt;html\u0026gt;\u0026lt;\/html\u0026gt;\u003C\/code\u003E robi si\u0119 zwyk\u0142e \u003Ccode\u003E%html\u003C\/code\u003E)\u003C\/p\u003E\n\u003Cp\u003EPotrafi\u0119 znale\u017a\u0107 tylko dwie wady ca\u0142ej tej rodziny technologii w por\u00f3wnaniu do \u003Cem\u003E\u015bwi\u0119tej tr\u00f3jcy\u003C\/em\u003E. Po pierwsze, tak jak przegl\u0105darki, tak samo frontendowi programi\u015bci tr\u00f3jc\u0119 znaj\u0105 z ca\u0142\u0105 pewno\u015bci\u0105, czego nie zawsze mo\u017cna powiedzie\u0107 o jej m\u0142odszym rodze\u0144stwie. Wi\u0119c je\u015bli kto\u015b dostanie po tobie projekt, w kt\u00f3rym u\u017cywa\u0142e\u015b Sassa czy CoffeeScriptu, mo\u017ce nie by\u0107 mu zbyt kolorowo. Z drugiej jednak strony, s\u0105 to przecie\u017c technologie \u003Cstrong\u003Ebardzo \u0142atwe do przyswojenia\u003C\/strong\u003E, a zarazem niezmiernie przydatne i wygodne. Wi\u0119c chyba tylko wy\u015bwiadczy\u0142by\u015b mu przys\u0142ug\u0119, prawda?\u003C\/p\u003E\n\u003Cp\u003EPo drugie natomiast, kompilowanie trwa i wymaga zachodu. Wystarczy jednak zainstalowa\u0107 \u003Ca href=\u0022http:\/\/bower.io\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Bowera\u003C\/a\u003E albo skonfigurowa\u0107 sobie watchera w \u003Ca href=\u0022https:\/\/www.jetbrains.com\/phpstorm\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E PhpStormie\u003C\/a\u003E, aby ka\u017cde zapisanie pliku automatycznie uruchamia\u0142o kompilacj\u0119. Naprawd\u0119, wygodniej ju\u017c si\u0119 tego zrobi\u0107 nie da!\u003C\/p\u003E\n\u003Cp\u003EA poza tym \u003Cstrong\u003Esame plusy\u003C\/strong\u003E. Je\u015bli tworzysz strony, a jeszcze nie znasz tych technologii \u2013 \u003Cstrong\u003Ekoniecznie je wypr\u00f3buj!\u003C\/strong\u003E Z odrobin\u0105 wprawy i do\u015bwiadczenia, po\u0142owa twoich frontendowych problem\u00f3w mo\u017ce znikn\u0105\u0107.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["coffeescript","frontend","haml","html","internet","javascript","kompilacja","less","programowanie","sass","scss","twig"],"hasMore":true,"image":"https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_small.jpeg","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_mini.jpeg\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022182.46679316888\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_mini.jpeg\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022182.46679316888\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E\n\u003Cp\u003EZ drugiej jednak strony t\u0119 sam\u0105 przeno\u015bno\u015b\u0107 mo\u017cna te\u017c uzna\u0107 za wad\u0119. Ca\u0142y Internet sprowadza si\u0119 bowiem ostatnio do tej \u015bwi\u0119tej tr\u00f3jcy: \u003Cstrong\u003EHTML5 + CSS3 + JS\u003C\/strong\u003E. Bo skoro te trzy potrafi\u0105 ju\u017c wszystko to, co kiedy\u015b umia\u0142y tylko \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/flash\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Flash\u003C\/a\u003E czy aplety \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/java\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Javy\u003C\/a\u003E, to po co ryzykowa\u0107 bezpiecze\u0144stwo witryny, zmusza\u0107 u\u017cytkownika do instalowania wtyczek i odbiera\u0107 sobie mo\u017cliwo\u015b\u0107 lepszej integracji element\u00f3w strony? Po prostu \u003Cem\u003Enie ma sensu\u003C\/em\u003E wychodzi\u0107 poza \u015bwi\u0119t\u0105 tr\u00f3jc\u0119. A jej rozw\u00f3j jest niestety ograniczony aktualizacjami przegl\u0105darek. Czy zatem jeste\u015bmy na ni\u0105 \u003Cstrong\u003Eskazani\u003C\/strong\u003E?\u003C\/p\u003E\n\u003Cp\u003ENa szcz\u0119\u015bcie nie! Istnieje ca\u0142a rodzina j\u0119zyk\u00f3w, kt\u00f3re bardzo sprytnie obchodz\u0105 ten problem. Wprowadzaj\u0105 ogromne ulepszenia i u\u0142atwienia, ale bez potrzeby interpretowania ich przez przegl\u0105darki! Po prostu po stronie programisty s\u0105 kompilowane do jednego z tych j\u0119zyk\u00f3w, kt\u00f3re ka\u017cda przegl\u0105darka rozumie.\u003C\/p\u003E\n\u003Cp\u003EPowiedzmy na przyk\u0142ad, \u017ce chcesz stworzy\u0107 w CSS klasy od \u003Ccode\u003Ecol-1\u003C\/code\u003E do \u003Ccode\u003Ecol-12\u003C\/code\u003E, z kt\u00f3rych ka\u017cda b\u0119dzie nadawa\u0142a DIV-owi szeroko\u015b\u0107 r\u00f3wn\u0105 ile\u015btam dwunastych szeroko\u015bci kontenera. W \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/thesassway.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Sass\u003C\/a\u003E\u003C\/strong\u003E zajmuje to trzy linijki:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E@for $i from 1 through 12\n  .col-#{$i}\n    width: $i\/12 * 100%\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EA jest kompilowane do takiego kodu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E.col-1 {\n  width: 8.33333%; }\n\n.col-2 {\n  width: 16.66667%; }\n\n.col-3 {\n  width: 25%; }\n\n.col-4 {\n  width: 33.33333%; }\n\n.col-5 {\n  width: 41.66667%; }\n\n.col-6 {\n  width: 50%; }\n\n.col-7 {\n  width: 58.33333%; }\n\n.col-8 {\n  width: 66.66667%; }\n\n.col-9 {\n  width: 75%; }\n\n.col-10 {\n  width: 83.33333%; }\n\n.col-11 {\n  width: 91.66667%; }\n\n.col-12 {\n  width: 100%; }\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EPierwszy z nich jest prosty, kr\u00f3tki i czytelny dla cz\u0142owieka, drugi natomiast zostanie zrozumiany przez wszystkie przegl\u0105darki. I wilk syty i owca ca\u0142a! Sass zawiera wiele element\u00f3w, kt\u00f3rych prostemu CSS-owi brakuje: zmiennych, instrukcji warunkowych, p\u0119tli, funkcji (tzw. mixins), zagnie\u017cd\u017ce\u0144, operacji arytmetycznych... O ile bardziej \u003Cstrong\u003Eelastyczny\u003C\/strong\u003E staje si\u0119 kod, gdy mo\u017cemy zdefiniowa\u0107 na przyk\u0142ad zmienn\u0105 \u003Ccode\u003E$navWidth: 300px\u003C\/code\u003E i u\u017cy\u0107 jej w pi\u0119ciu innych miejscach (r\u00f3wnie\u017c w wyra\u017ceniach arytmetycznych, np. \u003Ccode\u003Ewidth: $navWidth \/ 2 + 16px\u003C\/code\u003E), zamiast wsz\u0119dzie podawa\u0107 j\u0105 wprost. Ka\u017cda zmiana szeroko\u015bci nawigacji jest wtedy po prostu \u003Cstrong\u003Ebanalna\u003C\/strong\u003E, nie wymaga szukania wszystkich zale\u017cno\u015bci. O ile \u003Cstrong\u003Ekr\u00f3tszy i bardziej przejrzysty\u003C\/strong\u003E staje si\u0119 kod, je\u015bli mo\u017cemy cz\u0119sto powtarzaj\u0105ce si\u0119 elementy zamkn\u0105\u0107 w parametryzowane mixiny i po prostu si\u0119 do nich odwo\u0142ywa\u0107? \u015awietn\u0105 list\u0119 sassowych ficzer\u00f3w mo\u017cna znale\u017a\u0107 cho\u0107by na \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Sass_(stylesheet_language)\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Wikipedii\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cp\u003EPodobnymi do niego j\u0119zykami s\u0105 \u003Cstrong\u003EScss\u003C\/strong\u003E oras \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/lesscss.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Less\u003C\/a\u003E\u003C\/strong\u003E. Wol\u0119 jednak Sassa z jednego powodu \u2013 \u003Cstrong\u003Ebrak klamer\u003C\/strong\u003E. Skoro i tak w ka\u017cdym kodzie powinno si\u0119 stosowa\u0107 odpowiednie wci\u0119cia tabulatorami, to klamry staj\u0105 si\u0119 zwyczajnie zb\u0119dne. J\u0119zyk, kt\u00f3ry wymusza stosowanie wci\u0119\u0107 w kodzie po pierwsze wymaga mniej klepania w klawiatur\u0119, a po drugie daje gwarancj\u0119, \u017ce po kim by\u015bmy kodu nie przej\u0119li, zawsze przynajmniej pod tym wzgl\u0119dem b\u0119dzie on czytelny. Same plusy! Z tego samego za\u0142o\u017cenia wyszli chocia\u017cby tw\u00f3rcy \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.ruby-lang.org\/pl\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Rubiego\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.python.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Pythona\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E CoffeeScriptu\u003C\/a\u003E\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Cp\u003EA no w\u0142a\u015bnie, \u003Cstrong\u003ECoffeeScript\u003C\/strong\u003E. \u017bywy dow\u00f3d, \u017ce nawet tworzenie JavaScript\u00f3w mo\u017ce by\u0107 przyjemne (s\u0142owo daj\u0119, nie uwierzy\u0142bym, gdybym nie spr\u00f3bowa\u0142). W JS to dopiero jest nadmiar nawias\u00f3w i klamer:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Esse = new EventSource(Routing.generate(\u0027conversation_check\u0027));\nsse.addEventListener(\u0027conversation\u0027, function(e) {\n  if (e.data == \u0027test\u0027 || e.data == \u0027dev\u0027) { return; }\n  $.post(Routing.generate(\u0027conversation_fetch\u0027), { ids: e.data }, function(data) {\n    conversation.html(data);\n  });\n}, false);\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETa sama funkcjonalno\u015b\u0107 w CoffeeScripcie wygl\u0105da nast\u0119puj\u0105co:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Esse = new EventSource Routing.generate \u0027conversation_check\u0027\nsse.addEventListener \u0027conversation\u0027, (e) -\u0026gt;\n  return if e.data in [\u0027test\u0027, \u0027dev\u0027]\n  $.post(Routing.generate(\u0027conversation_fetch\u0027), { ids: e.data }, (data) -\u0026gt;\n    conversation.html(data)\n  )\n, false\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWystarczy\u0142o zast\u0105pienie sk\u0142adni \u003Ccode\u003Efunction(a) {...}\u003C\/code\u003E prostym \u003Ccode\u003E(a) -\u0026gt; ...\u003C\/code\u003E, zmiana klamer na wci\u0119cia oraz mo\u017cliwo\u015b\u0107 pomini\u0119cia niekt\u00f3rych nawias\u00f3w w parametrach funkcji \u2013 i voil\u00e0! Mniej klepania w klawiatur\u0119 i doszukiwania si\u0119 par nawias\u00f3w, a tre\u015bci tyle samo!\u003C\/p\u003E\n\u003Cp\u003ENie spos\u00f3b si\u0119 nachwali\u0107 wszystkich ficzer\u00f3w CoffeeScriptu... JSON-owe obiekty mo\u017cna w nim definiowa\u0107 podobnie jak w \u003Ca href=\u0022http:\/\/yaml.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E YAML-u\u003C\/a\u003E, p\u0119tl\u0119 mo\u017cna od 1 do 100 zawrze\u0107 w kr\u00f3ciutkim zapisie \u003Ccode\u003E1..100\u003C\/code\u003E, zmiennych nie trzeba deklarowa\u0107, mo\u017cna im przypisywa\u0107 warto\u015bci do wielu na raz (a nawet zamienia\u0107 je warto\u015bciami w jednej linijce: \u003Ccode\u003E[foo, bar] = [bar, foo]\u003C\/code\u003E i tyle!). Najlepiej po prostu przejrze\u0107 jego \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E stron\u0119 domow\u0105\u003C\/a\u003E i milcze\u0107 w \u003Cstrong\u003Ezachwycie\u003C\/strong\u003E!\u003C\/p\u003E\n\u003Cp\u003ER\u00f3wnie\u017c w przypadku HTML-a istnieje wiele technologii, kt\u00f3re pozwalaj\u0105 na wygenerowanie go na postawie bardziej wyrafinowanych j\u0119zyk\u00f3w. Lecz tutaj to troch\u0119 co innego. Mowa o template engines takich jak \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/twig.sensiolabs.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Twig\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.smarty.net\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Smarty\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/haml.info\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Haml\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.stuartellis.eu\/articles\/erb\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Erb\u003C\/a\u003E\u003C\/strong\u003E \u2013 one jednak s\u0105 kompilowane do j\u0119zyk\u00f3w wykonywanych po stronie serwera (PHP, Ruby, Python...), wi\u0119c niezbyt pasuj\u0105 do mojego zestawienia. (Nota bene w Hamlu jeszcze bardziej zredukowana jest klamrowa redundancja: z \u003Ccode\u003E\u0026lt;html\u0026gt;\u0026lt;\/html\u0026gt;\u003C\/code\u003E robi si\u0119 zwyk\u0142e \u003Ccode\u003E%html\u003C\/code\u003E)\u003C\/p\u003E\n\u003Cp\u003EPotrafi\u0119 znale\u017a\u0107 tylko dwie wady ca\u0142ej tej rodziny technologii w por\u00f3wnaniu do \u003Cem\u003E\u015bwi\u0119tej tr\u00f3jcy\u003C\/em\u003E. Po pierwsze, tak jak przegl\u0105darki, tak samo frontendowi programi\u015bci tr\u00f3jc\u0119 znaj\u0105 z ca\u0142\u0105 pewno\u015bci\u0105, czego nie zawsze mo\u017cna powiedzie\u0107 o jej m\u0142odszym rodze\u0144stwie. Wi\u0119c je\u015bli kto\u015b dostanie po tobie projekt, w kt\u00f3rym u\u017cywa\u0142e\u015b Sassa czy CoffeeScriptu, mo\u017ce nie by\u0107 mu zbyt kolorowo. Z drugiej jednak strony, s\u0105 to przecie\u017c technologie \u003Cstrong\u003Ebardzo \u0142atwe do przyswojenia\u003C\/strong\u003E, a zarazem niezmiernie przydatne i wygodne. Wi\u0119c chyba tylko wy\u015bwiadczy\u0142by\u015b mu przys\u0142ug\u0119, prawda?\u003C\/p\u003E\n\u003Cp\u003EPo drugie natomiast, kompilowanie trwa i wymaga zachodu. Wystarczy jednak zainstalowa\u0107 \u003Ca href=\u0022http:\/\/bower.io\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Bowera\u003C\/a\u003E albo skonfigurowa\u0107 sobie watchera w \u003Ca href=\u0022https:\/\/www.jetbrains.com\/phpstorm\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E PhpStormie\u003C\/a\u003E, aby ka\u017cde zapisanie pliku automatycznie uruchamia\u0142o kompilacj\u0119. Naprawd\u0119, wygodniej ju\u017c si\u0119 tego zrobi\u0107 nie da!\u003C\/p\u003E\n\u003Cp\u003EA poza tym \u003Cstrong\u003Esame plusy\u003C\/strong\u003E. Je\u015bli tworzysz strony, a jeszcze nie znasz tych technologii \u2013 \u003Cstrong\u003Ekoniecznie je wypr\u00f3buj!\u003C\/strong\u003E Z odrobin\u0105 wprawy i do\u015bwiadczenia, po\u0142owa twoich frontendowych problem\u00f3w mo\u017ce znikn\u0105\u0107.\u003C\/p\u003E","words":1075,"readTime":5,"lang":"pl"}}},"blog\/technology\/czysty-kod-w-praktyce-autoloader-w-php":{"key":"blog\/technology\/czysty-kod-w-praktyce-autoloader-w-php","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:30+02:00","publishedAt":"2015-04-06T19:40:00+02:00","group":null,"category":"blog","subcategory":"technology","slug":"czysty-kod-w-praktyce-autoloader-w-php"},"content":{"pl":{"slug":"czysty-kod-w-praktyce-autoloader-w-php","title":"\u201cCzysty kod\u201d w praktyce \u2013 Autoloader w PHP","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/czysty-kod-w-praktyce-autoloader-w-php_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022328\u0022 height=\u0022467\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAkCAYAAAB8DZEQAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHFUlEQVRIibWWy49dRxHGf9Xd55z7vnfGM\/Z4cCY2xA62ZBCWsyCOxQKRVaygOJHYskAsEH8AOzbAEikII3ZsvGHBBqRIYYEwSBYQSHBisLHj1\/jaM+N53vd5dBeLM7Fn\/AhCiE86On1Kp+urqq6uKnHfeFt1bQkzfxB\/7zbUWojPkFobTSpgE0gzUAURGG5Sfe8c4jPqtRpplpEXBc4YojgiiWI2+30qSUy6vc\/p\/euEpEkoBDnyEhiLOodmOYigkxSptAihJJHWDNmRV4mv\/IajR16gWqmQZhmD0Yg7i3c5+\/oZ7i8tAdC9v8Sly\/9A3LfPq8Yt1FoIigSPisEYwYtgfMCrlp4AxhjwGebBDbQUIKqAAApphsQRr37xAFfvbXH7+m2cDlK0mqG2VEgcEbWraJbjJxmSROyzMC4C3lqsKhEVsr2HUe8ZiAFguuKw1qJZjrOGcXMGpnr4juDoLyNBMTN7UVNu8MMx6gNUYqoGXOyYqQpYQ+6VucQyzDz9UcqgPwExNCJHM7aMKxH1imNrbcDKMMM0azgabUJrD7VKzELFEDYHdG3MkdkW66mnHRuSakwalPupJzfKnSB4DCGK6DSF4ANDHxjnQjCG9VFBOslx1hJZg1NiJMuZiuvkvTG16RbzCHFkmbEGDcok8wRnEQVnDWmAQoSaM4wzaMSOXh4woUzAQVZgnaXICsQ5XNxukC4u0vU59dlpkt6EOLIspgGngbo15AK9AM0kouospvBsjQscSiQQO0MQgxhhmHmMCM5ZPKCbE0x26QLR84eQ6SmGmccHJbOWPARGQRn7gPdKoeBDQADvA5rm6CRHjGGEYK2h4gyRAQ0BP5ogaY5WEwyHThKiGIwgkxStJhRFwOcFVaCKoqoQFFXwWUHIPSioM6gRYiDNCjaGGUXmCapIHKGALq\/iSDOCgq71kHaDce6ZFaVai7F5wUaudKoRFcBZYeADMcpsxZIAq5knUmXWCRpgrLA5yrGRo3AG027iIEdvfowe+hzGe4os455XNPEYlCCG8SiDOEJ9gYiAArkHVQRY8xAmGRoUC9gkIss9OhzB+jqOtbtw9BSSe0LwSF5AFCFrGzDV5qUDDb51aoEPV0a8MFOjGlsu3esTGeFQp8LaOGc4zjn92Sku3+vxzrV1vnKow48u3EGLgOl0MCR1zGgC1sBwBJ1WaWnICCFwtO04\/5cuP7l4l6FX3v79LU4caNFJLO2q43K3x7kLN7m9PuIHv7vFD197kSvdHloENMvQfh\/HaJNggdX7aKONpiniU3ARMpqg6YTaMOd5zZm2cHV9zB9vbPCvpT7v3drg3Nlj\/LO7hRQFk5VNLl9b5td\/uIqiUIxhsoWVhRPf5+b7EEUYiSFLYfVOWeKDZ2VpjTMn9rPQdARjaPiCq0s9ltf6vPGFOcIk5d3371DHs7K6ii0mXOmu47Mhpr8K6QZijn9dw\/Jt5NhpJICONiEdwtxhJB2BceAq6KQPU\/NQiaAINOtVvnzyGNPTbaxA4hQxMXc\/vk67EfPLn\/4Mam2kGOL0yp9gahb92ztoow3DHtRbsLaI5ilUalDkpYd79kEI4BxUEw6ffYVrf77I9NwcqRUa07Nc+tUvePnNN9H71yF4KFIcGmB9pewXw37ZEwY9SnzSJ7ax9eDhUmf3cO3Cb5man2d6bh93\/v5Xqo0Gh459HmdtaSyAAZFon6rKkwrLlrRDtqMxAcY52rN7sVHEzMIC436fraUlOvPzrC0u0l9dLXeL4ngm5Bnf5bsSOb526ksYEbZ6PUyzw6AV0W61eBApFx+sPtzinlSyG85arBVAMEYIIeCDUqtVGA4GLCx8hjxPmZmZpttdYmZPh\/F4vFvH7tA8idOvnOS73\/km\/X4fYyzLy8t8+NEVTp9+mU67Sbfb5fjxo9RrVfI854MPPqLeqLNT7\/aZPDtoRgwilJMKoFpWY4SyjsHDcUmAELSsvqqAIvLQk6cdfGlJUN02KOyQCw+ZdkXi8SQp9bptf0BMeQeeCN3TyXe\/H5fvXpfjyVffglOvlWS6bYHuXPPoe6d818Nj60eelWey8CJsrUJrqrSgUod0BHkOSRWyCRhTeitSPiGAi8B72HgAvU2eBhHdJgnC1FST2ZkOaZpRr1VJ07Ts5aokSYL3Aecsw9GYdqvB+kaPpeW1MpgiqAaedka7SA4e3M\/CgX0kSYwq5HlOUXji2JHEMS5yDPpDKtUKRVEwmUyo1+uEEOh2V5ikOSLC4t0lsrx4uidiSgOsNYRQDlDGSJlEqrjI4QtP0IBsW6zbqWutoch9OT+H3cnwiORT7sn\/CpFPsus\/\/\/pfK3\/uwH7arSbwkGR38XsyFR8n\/JSUFYsA3\/vxOc688TrwRO161iXbiadfOADiGsw8h6YD3j3\/c65fu1FSm3huu5\/8fyCi\/BsCrKXMv6hFYQAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/czysty-kod-w-praktyce-autoloader-w-php_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022328\u0022 height=\u0022467\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKsi\u0105\u017cka Roberta C. Martina \u003Ca href=\u0022http:\/\/helion.pl\/ksiazki\/czysty-kod-podrecznik-dobrego-programisty-robert-c-martin,czykov.htm\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E \u201cCzysty kod\u201d\u003C\/a\u003E bije rekordy sprzeda\u017cy w\u015br\u00f3d pozycji dotycz\u0105cych szeroko poj\u0119tej informatyki. Wstyd wi\u0119c \u017cebym jej nie przeczyta\u0142, no nie? I zdecydowanie polecam j\u0105 ka\u017cdemu programi\u015bcie, kt\u00f3ry chcia\u0142by by\u0107 jak najlepszy w tym, co robi.\u003C\/p\u003E\n\u003Cp\u003EChcia\u0142bym tutaj pokaza\u0107 na konkretnym fragmencie kodu, jak wiele mo\u017ce zmieni\u0107 stosowanie si\u0119 do zasad przedstawionych przez Martina. Na przyk\u0142adzie autoloadera.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/czysty-kod-w-praktyce-autoloader-w-php_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022328\u0022 height=\u0022467\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAkCAYAAAB8DZEQAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHFUlEQVRIibWWy49dRxHGf9Xd55z7vnfGM\/Z4cCY2xA62ZBCWsyCOxQKRVaygOJHYskAsEH8AOzbAEikII3ZsvGHBBqRIYYEwSBYQSHBisLHj1\/jaM+N53vd5dBeLM7Fn\/AhCiE86On1Kp+urqq6uKnHfeFt1bQkzfxB\/7zbUWojPkFobTSpgE0gzUAURGG5Sfe8c4jPqtRpplpEXBc4YojgiiWI2+30qSUy6vc\/p\/euEpEkoBDnyEhiLOodmOYigkxSptAihJJHWDNmRV4mv\/IajR16gWqmQZhmD0Yg7i3c5+\/oZ7i8tAdC9v8Sly\/9A3LfPq8Yt1FoIigSPisEYwYtgfMCrlp4AxhjwGebBDbQUIKqAAApphsQRr37xAFfvbXH7+m2cDlK0mqG2VEgcEbWraJbjJxmSROyzMC4C3lqsKhEVsr2HUe8ZiAFguuKw1qJZjrOGcXMGpnr4juDoLyNBMTN7UVNu8MMx6gNUYqoGXOyYqQpYQ+6VucQyzDz9UcqgPwExNCJHM7aMKxH1imNrbcDKMMM0azgabUJrD7VKzELFEDYHdG3MkdkW66mnHRuSakwalPupJzfKnSB4DCGK6DSF4ANDHxjnQjCG9VFBOslx1hJZg1NiJMuZiuvkvTG16RbzCHFkmbEGDcok8wRnEQVnDWmAQoSaM4wzaMSOXh4woUzAQVZgnaXICsQ5XNxukC4u0vU59dlpkt6EOLIspgGngbo15AK9AM0kouospvBsjQscSiQQO0MQgxhhmHmMCM5ZPKCbE0x26QLR84eQ6SmGmccHJbOWPARGQRn7gPdKoeBDQADvA5rm6CRHjGGEYK2h4gyRAQ0BP5ogaY5WEwyHThKiGIwgkxStJhRFwOcFVaCKoqoQFFXwWUHIPSioM6gRYiDNCjaGGUXmCapIHKGALq\/iSDOCgq71kHaDce6ZFaVai7F5wUaudKoRFcBZYeADMcpsxZIAq5knUmXWCRpgrLA5yrGRo3AG027iIEdvfowe+hzGe4os455XNPEYlCCG8SiDOEJ9gYiAArkHVQRY8xAmGRoUC9gkIss9OhzB+jqOtbtw9BSSe0LwSF5AFCFrGzDV5qUDDb51aoEPV0a8MFOjGlsu3esTGeFQp8LaOGc4zjn92Sku3+vxzrV1vnKow48u3EGLgOl0MCR1zGgC1sBwBJ1WaWnICCFwtO04\/5cuP7l4l6FX3v79LU4caNFJLO2q43K3x7kLN7m9PuIHv7vFD197kSvdHloENMvQfh\/HaJNggdX7aKONpiniU3ARMpqg6YTaMOd5zZm2cHV9zB9vbPCvpT7v3drg3Nlj\/LO7hRQFk5VNLl9b5td\/uIqiUIxhsoWVhRPf5+b7EEUYiSFLYfVOWeKDZ2VpjTMn9rPQdARjaPiCq0s9ltf6vPGFOcIk5d3371DHs7K6ii0mXOmu47Mhpr8K6QZijn9dw\/Jt5NhpJICONiEdwtxhJB2BceAq6KQPU\/NQiaAINOtVvnzyGNPTbaxA4hQxMXc\/vk67EfPLn\/4Mam2kGOL0yp9gahb92ztoow3DHtRbsLaI5ilUalDkpYd79kEI4BxUEw6ffYVrf77I9NwcqRUa07Nc+tUvePnNN9H71yF4KFIcGmB9pewXw37ZEwY9SnzSJ7ax9eDhUmf3cO3Cb5man2d6bh93\/v5Xqo0Gh459HmdtaSyAAZFon6rKkwrLlrRDtqMxAcY52rN7sVHEzMIC436fraUlOvPzrC0u0l9dLXeL4ngm5Bnf5bsSOb526ksYEbZ6PUyzw6AV0W61eBApFx+sPtzinlSyG85arBVAMEYIIeCDUqtVGA4GLCx8hjxPmZmZpttdYmZPh\/F4vFvH7tA8idOvnOS73\/km\/X4fYyzLy8t8+NEVTp9+mU67Sbfb5fjxo9RrVfI854MPPqLeqLNT7\/aZPDtoRgwilJMKoFpWY4SyjsHDcUmAELSsvqqAIvLQk6cdfGlJUN02KOyQCw+ZdkXi8SQp9bptf0BMeQeeCN3TyXe\/H5fvXpfjyVffglOvlWS6bYHuXPPoe6d818Nj60eelWey8CJsrUJrqrSgUod0BHkOSRWyCRhTeitSPiGAi8B72HgAvU2eBhHdJgnC1FST2ZkOaZpRr1VJ07Ts5aokSYL3Aecsw9GYdqvB+kaPpeW1MpgiqAaedka7SA4e3M\/CgX0kSYwq5HlOUXji2JHEMS5yDPpDKtUKRVEwmUyo1+uEEOh2V5ikOSLC4t0lsrx4uidiSgOsNYRQDlDGSJlEqrjI4QtP0IBsW6zbqWutoch9OT+H3cnwiORT7sn\/CpFPsus\/\/\/pfK3\/uwH7arSbwkGR38XsyFR8n\/JSUFYsA3\/vxOc688TrwRO161iXbiadfOADiGsw8h6YD3j3\/c65fu1FSm3huu5\/8fyCi\/BsCrKXMv6hFYQAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/czysty-kod-w-praktyce-autoloader-w-php_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022328\u0022 height=\u0022467\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKsi\u0105\u017cka Roberta C. Martina \u003Ca href=\u0022http:\/\/helion.pl\/ksiazki\/czysty-kod-podrecznik-dobrego-programisty-robert-c-martin,czykov.htm\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E \u201cCzysty kod\u201d\u003C\/a\u003E bije rekordy sprzeda\u017cy w\u015br\u00f3d pozycji dotycz\u0105cych szeroko poj\u0119tej informatyki. Wstyd wi\u0119c \u017cebym jej nie przeczyta\u0142, no nie? I zdecydowanie polecam j\u0105 ka\u017cdemu programi\u015bcie, kt\u00f3ry chcia\u0142by by\u0107 jak najlepszy w tym, co robi.\u003C\/p\u003E\n\u003Cp\u003EChcia\u0142bym tutaj pokaza\u0107 na konkretnym fragmencie kodu, jak wiele mo\u017ce zmieni\u0107 stosowanie si\u0119 do zasad przedstawionych przez Martina. Na przyk\u0142adzie autoloadera.\u003C\/p\u003E\n\u003Cp\u003ETylko najpierw kr\u00f3tki wst\u0119p, co to w og\u00f3le jest \u201cautoloader\u201d. Ot\u00f3\u017c: przy ka\u017cdym \u017c\u0105daniu do serwera uruchamiana jest nowa instancja interpretera PHP. Aby nie musia\u0142 on \u0142adowa\u0107 wszystkich plik\u00f3w .php obecnych w projekcie (a potrafi\u0105 ich by\u0107 tysi\u0105ce), lecz tylko te, z kt\u00f3rych akurat w tym \u017c\u0105daniu skorzysta, u\u017cywany jest mechanizm auto\u0142adowania. Dzia\u0142a to tak, \u017ce kiedy interpreter PHP trafi na u\u017cycie klasy, kt\u00f3rej nie zna, odpyta o ni\u0105 po kolei autoloadery, kt\u00f3re ma zarejestrowane. Je\u015bli kt\u00f3ry\u015b z nich zwr\u00f3ci true, oznacza to, \u017ce znalaz\u0142 on plik, w kt\u00f3rym dana klasa powinna si\u0119 znajdowa\u0107, i do\u0142\u0105czy\u0142 go. W przeciwnym razie interpreter pyta kolejnego autoloadera w kolejce, a dopiero je\u015bli wszystkie zawiod\u0105 \u2013 wyrzuca fatal error \u201cClass not found\u201d.\u003C\/p\u003E\n\u003Cp\u003ENapisa\u0142em sobie kiedy\u015b ma\u0142\u0105 klas\u0119 autoloadera, a raczej poprzerabia\u0142em jak\u0105\u015b znalezion\u0105 na necie. Wygl\u0105da\u0142a tak:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-meta\u0022\u003E\u0026lt;?php\u003C\/span\u003E\n\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EAutoloader\u003C\/span\u003E \u003C\/span\u003E{\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E $namespace;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E $path;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E $valid = \u003Cspan class=\u0022hljs-keyword\u0022\u003Efalse\u003C\/span\u003E;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003E__construct\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($namespace, $path = \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\u0027\u003C\/span\u003E)\u003C\/span\u003E \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;namespace = $namespace;\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;path = $path;\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;valid = \u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E;\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003Eautoload\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($className)\u003C\/span\u003E \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ is this autoloader responsible for that particular class?\u003C\/span\u003E\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (substr($className,\u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E,strlen(\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;namespace)) === \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;namespace) {\n            $path = \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;path . str_replace(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\\\\\u0027\u003C\/span\u003E,\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/\u0027\u003C\/span\u003E, ltrim( $className, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\\\\\u0027\u003C\/span\u003E)) . \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.php\u0027\u003C\/span\u003E;\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (file_exists($path)) {\n                \u003Cspan class=\u0022hljs-keyword\u0022\u003Erequire_once\u003C\/span\u003E($path);\n                \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E;\n            } \u003Cspan class=\u0022hljs-keyword\u0022\u003Eelse\u003C\/span\u003E {\n                \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ if not straightforward, maybe try \u0022common\u0022 class files\u003C\/span\u003E\n                \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ eg. \u0022Exceptions\u0022 for \u0022NotFoundException\u0022;\u003C\/span\u003E\n                $slashPos = strrpos($className,\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\\\\\u0027\u003C\/span\u003E,\u003Cspan class=\u0022hljs-number\u0022\u003E-1\u003C\/span\u003E) + \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E;\n                $base = substr($className,\u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E,$slashPos);\n                $classPure = substr($className,$slashPos);\n                preg_match_all(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/(?:^|[A-Z])[a-z]+\/\u0027\u003C\/span\u003E,$classPure,$matches);\n                $path = \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;path . str_replace(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\\\\\u0027\u003C\/span\u003E,\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/\u0027\u003C\/span\u003E, ltrim( $base . end($matches[\u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E]) . \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027s\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\\\\\u0027\u003C\/span\u003E)) . \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.php\u0027\u003C\/span\u003E;\n                \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (file_exists($path)) {\n                    \u003Cspan class=\u0022hljs-keyword\u0022\u003Erequire_once\u003C\/span\u003E($path);\n                    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E;\n                } \u003Cspan class=\u0022hljs-keyword\u0022\u003Eelse\u003C\/span\u003E {\n                    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Efalse\u003C\/span\u003E; \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ damn, maybe other autoloaders will find something\u003C\/span\u003E\n                }\n            }\n        } \u003Cspan class=\u0022hljs-keyword\u0022\u003Eelse\u003C\/span\u003E {\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Efalse\u003C\/span\u003E; \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ no, let the other autoloaders handle that\u003C\/span\u003E\n        }\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003Eregister\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;valid) {\n            spl_autoload_register(\u003Cspan class=\u0022hljs-keyword\u0022\u003Earray\u003C\/span\u003E(\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027autoload\u0027\u003C\/span\u003E));\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;valid = \u003Cspan class=\u0022hljs-keyword\u0022\u003Efalse\u003C\/span\u003E; \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/in order not to register it twice\u003C\/span\u003E\n        }\n    }\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EPrzyk\u0142adowe u\u017cycie mojego autoloadera wygl\u0105da nast\u0119puj\u0105co:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-meta\u0022\u003E\u0026lt;?php\u003C\/span\u003E\n$autoloader = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E Autoloader(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027Micrus\\\\\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-keyword\u0022\u003E__DIR__\u003C\/span\u003E . \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/vendor\/\u0027\u003C\/span\u003E);\n$autoloader-\u0026gt;register();\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETworzymy nowy autoloader maj\u0105cy obs\u0142ugiwa\u0107 wszystkie klasy w przestrzeni nazw \u201cMicrus\u201d i szukaj\u0105cy ich w katalogu \u201cvendor\u201d, gdzie klasy s\u0105 umieszczone w podfolderach zgodnie ze swoj\u0105 przestrzeni\u0105 nazw. Oznacza to, \u017ce je\u015bli gdzie\u015b w kodzie b\u0119dziemy chcieli stworzy\u0107 nowy obiekt klasy \u003Ccode\u003EMicrus\\Foo\\Bar\\MyClass\u003C\/code\u003E, to powinna si\u0119 ona znajdowa\u0107 w pliku \u003Ccode\u003E\/vendor\/Micrus\/Foo\/Bar\/MyClass.php\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EDo tego dochodzi jeszcze pewien ma\u0142y feature (niezgodny z \u003Ca href=\u0022http:\/\/www.php-fig.org\/psr\/psr-4\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E PSR-4\u003C\/a\u003E). Ot\u00f3\u017c je\u015bli chcemy zgrupowa\u0107 kilka podobnych klas w jednym pliku, mo\u017cemy zrobi\u0107 to w bardzo prosty spos\u00f3b. Mamy na przyk\u0142ad klasy wyj\u0105tk\u00f3w, kt\u00f3re potrafi\u0105 by\u0107 naprawd\u0119 malutkie i czasem niewygodnie jest rozbija\u0107 je na osobne pliki. Nazywamy je wszystkie u\u017cywaj\u0105c \u003Ca href=\u0022http:\/\/pl.wikipedia.org\/wiki\/PascalCase\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E PascalCase\u003C\/a\u003E z \u201cException\u201d jako ostatnim s\u0142owem i umieszczamy w pliku \u003Ccode\u003EExceptions.php\u003C\/code\u003E (z dodatkowym -s). M\u00f3j autoloader obs\u0142u\u017cy taki przypadek.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-meta\u0022\u003E\u0026lt;?php\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Enamespace\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EMicrus\u003C\/span\u003E;\n\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EConfigFileException\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eextends\u003C\/span\u003E \\\u003Cspan class=\u0022hljs-title\u0022\u003EException\u003C\/span\u003E \u003C\/span\u003E{ }\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003ENotFoundException\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eextends\u003C\/span\u003E \\\u003Cspan class=\u0022hljs-title\u0022\u003EException\u003C\/span\u003E \u003C\/span\u003E{ \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprotected\u003C\/span\u003E $code = \u003Cspan class=\u0022hljs-number\u0022\u003E404\u003C\/span\u003E; }\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003ECacheException\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eextends\u003C\/span\u003E \\\u003Cspan class=\u0022hljs-title\u0022\u003EException\u003C\/span\u003E \u003C\/span\u003E{ }\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003ERouteNotFoundException\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eextends\u003C\/span\u003E \\\u003Cspan class=\u0022hljs-title\u0022\u003EException\u003C\/span\u003E \u003C\/span\u003E{ \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprotected\u003C\/span\u003E $code = \u003Cspan class=\u0022hljs-number\u0022\u003E404\u003C\/span\u003E; }\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EInvalidArgumentException\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eextends\u003C\/span\u003E \\\u003Cspan class=\u0022hljs-title\u0022\u003EException\u003C\/span\u003E \u003C\/span\u003E{ }\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EUnauthorisedException\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eextends\u003C\/span\u003E \\\u003Cspan class=\u0022hljs-title\u0022\u003EException\u003C\/span\u003E \u003C\/span\u003E{ \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprotected\u003C\/span\u003E $code = \u003Cspan class=\u0022hljs-number\u0022\u003E403\u003C\/span\u003E; }\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EArgvException\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eextends\u003C\/span\u003E \\\u003Cspan class=\u0022hljs-title\u0022\u003EException\u003C\/span\u003E \u003C\/span\u003E{ }\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EDatabaseException\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eextends\u003C\/span\u003E \\\u003Cspan class=\u0022hljs-title\u0022\u003EException\u003C\/span\u003E \u003C\/span\u003E{ }\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EKod autoloadera nie wygl\u0105da \u017ale (a przynajmniej widzia\u0142em gorsze). Ale pierwsze spojrzenie na metod\u0119 \u201cautoload\u201d potrafi przerazi\u0107. Jest okropnie nieczytelna, mimo \u017ce komentarze obja\u015bniaj\u0105 jej dzia\u0142anie. Potrzeba troch\u0119 wysi\u0142ku, \u017ceby dowiedzie\u0107 si\u0119, co konkretnie robi.\u003C\/p\u003E\n\u003Cp\u003EWszyscy ucz\u0105, zeby pisa\u0107 komentarze do kodu. Du\u017co komentarzy. Nawet je\u015bli wydaje ci si\u0119 to bezsensowne, bo przecie\u017c rozumiesz, co napisa\u0142e\u015b, to musisz bra\u0107 pod uwag\u0119, \u017ce je\u015bli kod trafi w r\u0119ce kogo innego, albo i ty sam zajrzysz do niego rok czy dwa p\u00f3\u017aniej, to rozszyfrowanie go mo\u017ce ju\u017c nie by\u0107 takie proste.\u003C\/p\u003E\n\u003Cp\u003EMartin natomiast uczy czego innego. Dobry kod wymaga tylko znikomej liczby komentarzy. Je\u015bli ich potrzebujesz, by zrozumie\u0107, co si\u0119 dzieje, znaczy \u017ce kod jest nieczytelny. No i komentarze s\u0105 w pewnym sensie \u003Cem\u003Eniebezpieczne\u003C\/em\u003E: zapominamy je pisa\u0107, zapominamy je aktualizowa\u0107, boimy si\u0119 je usuwa\u0107, szybko trac\u0105 na wa\u017cno\u015bci...\u003C\/p\u003E\n\u003Cp\u003ESp\u00f3jrzcie na kod autoloadera po serii poprawek:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-meta\u0022\u003E\u0026lt;?php\u003C\/span\u003E\n\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EAutoloader\u003C\/span\u003E\n\u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E $namespace;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E $path;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E $registered = \u003Cspan class=\u0022hljs-keyword\u0022\u003Efalse\u003C\/span\u003E;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003E__construct\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($namespace, $path = \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.\u0027\u003C\/span\u003E)\u003C\/span\u003E\n    \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;namespace = \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;addEndingSlash($namespace, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\\\\\u0027\u003C\/span\u003E);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;path = \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;addEndingSlash($path, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/\u0027\u003C\/span\u003E);\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EaddEndingSlash\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($word, $slash = \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/\u0027\u003C\/span\u003E)\u003C\/span\u003E\n    \u003C\/span\u003E{\n        $lastCharacter = substr($word, \u003Cspan class=\u0022hljs-number\u0022\u003E-1\u003C\/span\u003E);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $lastCharacter == $slash ? $word : $word . $slash;\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003Eautoload\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($className)\u003C\/span\u003E\n    \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;isNotResponsibleForClass($className)) {\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Efalse\u003C\/span\u003E;\n        }\n\n        $path = \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;classNameToFilePath($className);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (file_exists($path)) {\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Erequire_once\u003C\/span\u003E($path);\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E;\n        }\n\n        $groupName = \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;classNameToGroupName($className);\n        $path = \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;classNameToFilePath($groupName);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (file_exists($path)) {\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Erequire_once\u003C\/span\u003E($path);\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E;\n        }\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Efalse\u003C\/span\u003E;\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EisNotResponsibleForClass\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($className)\u003C\/span\u003E\n    \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E substr($className, \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E, strlen(\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;namespace)) !== \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;namespace;\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EclassNameToFilePath\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($className)\u003C\/span\u003E\n    \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;path . str_replace(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\\\\\u0027\u003C\/span\u003E,\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/\u0027\u003C\/span\u003E, ltrim( $className, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\\\\\u0027\u003C\/span\u003E)) . \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.php\u0027\u003C\/span\u003E;\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EclassNameToGroupName\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($className)\u003C\/span\u003E\n    \u003C\/span\u003E{\n        $slashPos = strrpos($className,\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\\\\\u0027\u003C\/span\u003E,\u003Cspan class=\u0022hljs-number\u0022\u003E-1\u003C\/span\u003E) + \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E;\n        $base = substr($className,\u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E,$slashPos);\n        $classPure = substr($className,$slashPos);\n        preg_match_all(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/(?:^|[A-Z])[a-z]+\/\u0027\u003C\/span\u003E,$classPure,$matches);\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $base . end($matches[\u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E]) . \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027s\u0027\u003C\/span\u003E;\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003Eregister\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E\n    \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;registered) { \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Efalse\u003C\/span\u003E; }\n        spl_autoload_register(\u003Cspan class=\u0022hljs-keyword\u0022\u003Earray\u003C\/span\u003E(\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027autoload\u0027\u003C\/span\u003E));\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;registered = \u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E;\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E;\n    }\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWystarczy zerkn\u0105\u0107 na funkcj\u0119 autoload, \u017ceby wiedzie\u0107, co robi. Ba, nawet nie trzeba zna\u0107 \u017cadnego j\u0119zyka programowania! To\u017c to niemal czysty angielski: \u201cif this is not responsible for class \u2018class name\u2019, return false\u201d. Nie mamy poj\u0119cia \u003Cem\u003Ejak\u003C\/em\u003E funkcja to robi, ale wida\u0107 jak na d\u0142oni \u003Cem\u003Eco\u003C\/em\u003E takiego wykonuje.\u003C\/p\u003E\n\u003Cp\u003E\u003Cem\u003E\u201cJak\u201d\u003C\/em\u003E natomiast znajduje si\u0119 w osobnych, prywatnych metodach. Rozdzielili\u015bmy zatem od siebie r\u00f3\u017cne \u003Cem\u003Ewarstwy abstrakcji\u003C\/em\u003E, kt\u00f3re wcze\u015bniej by\u0142y zlane w jedn\u0105, brzydk\u0105 funkcj\u0119. Bo je\u015bli kto\u015b zajrzy do naszego kodu, to najprawdopodobniej nie b\u0119dzie potrzebowa\u0142 znajomo\u015bci wszystkiego, co tam naskrobali\u015bmy, lecz przyjdzie z jakim\u015b jednym konkretnym zadaniem: \u201cogarn\u0105\u0107 jak mniej wi\u0119cej dzia\u0142a ten autoloader\u201d, \u201czmieni\u0107 format nazwy \u2018zbiorowego pliku\u2019\u201d, \u201czmieni\u0107 kolejno\u015b\u0107 sprawdzania potencjalnych plik\u00f3w\u201d itp. I dlatego rozdzielenie warstw abstrakcji tak bardzo upro\u015bci mu prac\u0119.\u003C\/p\u003E\n\u003Cp\u003ENa pierwszy rzut oka wydawa\u0142oby si\u0119 sensowniejsze stworzenie metody isResponsibleForClass zamiast jej negacji \u2013 isNotResponsibleForClass. Kto normalny pyta\u0142by klas\u0119, czy \u003Cem\u003Enie jest\u003C\/em\u003E za co\u015b odpowiedzialna? Odpowied\u017a \u201ctak, nie jestem\u201d tylko niepotrzebnie by wszystko zagmatwa\u0142a, prawda? No w\u0142a\u015bnie niekoniecznie. U\u017cycie tej metody jest tylko jedno i sprowadza si\u0119 do \u201cje\u015bli nie jeste\u015b za to odpowiedzialna, to daj sobie spok\u00f3j\u201d. Zapisanie tego warunku jako \u003Ccode\u003Eif (!$this-\u0026gt;isResponsibleForClass($className))\u003C\/code\u003E zmniejsza czytelno\u015b\u0107, poniewa\u017c tego wykrzyknika prawie nie wida\u0107. Zawsze zapominamy o wykrzyknikach...\u003C\/p\u003E\n\u003Cp\u003EZanegowanie dopad\u0142o te\u017c zmienn\u0105 \u003Ccode\u003Evalid\u003C\/code\u003E. Zawsze gdy j\u0105 widzia\u0142em, musia\u0142em si\u0119 zastanowi\u0107, po co ona komu. Kiedy niby autoloader staje si\u0119 \u201cinvalid\u201d? A chodzi przecie\u017c o to, \u017ce autoloader mo\u017ce by\u0107 albo \u003Cem\u003Ejeszcze nie zarejestrowany\u003C\/em\u003E, albo \u003Cem\u003Eju\u017c zarejestrowany\u003C\/em\u003E. Czemu wi\u0119c nie zmieni\u0107 nazwy tej w\u0142a\u015bciwo\u015bci na \u003Ccode\u003Eregistered\u003C\/code\u003E? Teraz metoda \u003Ccode\u003Eregister()\u003C\/code\u003E staje si\u0119 bardzo czytelna: \u201cje\u015bli jeste\u015b zarejestrowany, to ju\u017c wi\u0119cej si\u0119 nie rejestruj\u201d.\u003C\/p\u003E\n\u003Cp\u003EBazowy namespace powinien ko\u0144czy\u0107 si\u0119 backslashem, aby unikn\u0105\u0107 takich sytuacji, gdy chcemy na przyk\u0142ad przechwyci\u0107 klasy \u201cJava\/...\u201d, a zgarniemy tak\u017ce i \u201cJavascript\/...\u201d. Dla zachowania jednorodno\u015bci, to samo powinno dotyczy\u0107 drugiego parametru konstruktora (\u015bcie\u017cki do folderu). Ale po co cz\u0142owiekowi, kt\u00f3ry chce u\u017cy\u0107 naszego autoloadera, kaza\u0107 si\u0119 zastanawia\u0107 nad tym, czy wymagamy slasha czy nie? Mo\u017ce lepiej po prostu sprawd\u017amy, czy slash jest na ko\u0144cu parametru, i doklejmy go, je\u015bli nie? Dodanie metody \u003Ccode\u003EaddEndingSlash\u003C\/code\u003E sprawi\u0142o, \u017ce nie tylko sama klasa jest prostsza, ale tak\u017ce i jej u\u017cycie na zewn\u0105trz.\u003C\/p\u003E\n\u003Cp\u003ETym oto sposobem w nowym kodzie jest zdecydowanie mniej zagnie\u017cd\u017ce\u0144, metody s\u0105 kr\u00f3tsze, a ka\u017cda zajmuje si\u0119 dok\u0142adnie jedn\u0105 rzecz\u0105 na jednym poziomie abstrakcji.\u003C\/p\u003E\n\u003Cp\u003EI jak? Kt\u00f3r\u0105 wersj\u0119 wolicie? Kt\u00f3ra nie marnuje czasu programisty pr\u00f3buj\u0105cego j\u0105 zrozumie\u0107?\u003C\/p\u003E\n\u003Cp\u003E\u201cCzysty kod\u201d warto przeczyta\u0107, warto do niego wraca\u0107 i \u2013 przede wszystkim \u2013 warto stosowa\u0107 si\u0119 do zawartych w nim rad.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["czytelno\u015b\u0107","informatyka","kod","ksi\u0105\u017cka","php","programowanie"],"hasMore":true,"image":"https:\/\/avris.it\/image\/czysty-kod-w-praktyce-autoloader-w-php_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/czysty-kod-w-praktyce-autoloader-w-php_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/czysty-kod-w-praktyce-autoloader-w-php_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022341.70731707317\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKsi\u0105\u017cka Roberta C. Martina \u003Ca href=\u0022http:\/\/helion.pl\/ksiazki\/czysty-kod-podrecznik-dobrego-programisty-robert-c-martin,czykov.htm\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E \u201cCzysty kod\u201d\u003C\/a\u003E bije rekordy sprzeda\u017cy w\u015br\u00f3d pozycji dotycz\u0105cych szeroko poj\u0119tej informatyki. Wstyd wi\u0119c \u017cebym jej nie przeczyta\u0142, no nie? I zdecydowanie polecam j\u0105 ka\u017cdemu programi\u015bcie, kt\u00f3ry chcia\u0142by by\u0107 jak najlepszy w tym, co robi.\u003C\/p\u003E\n\u003Cp\u003EChcia\u0142bym tutaj pokaza\u0107 na konkretnym fragmencie kodu, jak wiele mo\u017ce zmieni\u0107 stosowanie si\u0119 do zasad przedstawionych przez Martina. Na przyk\u0142adzie autoloadera.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/czysty-kod-w-praktyce-autoloader-w-php_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/czysty-kod-w-praktyce-autoloader-w-php_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022341.70731707317\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKsi\u0105\u017cka Roberta C. Martina \u003Ca href=\u0022http:\/\/helion.pl\/ksiazki\/czysty-kod-podrecznik-dobrego-programisty-robert-c-martin,czykov.htm\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E \u201cCzysty kod\u201d\u003C\/a\u003E bije rekordy sprzeda\u017cy w\u015br\u00f3d pozycji dotycz\u0105cych szeroko poj\u0119tej informatyki. Wstyd wi\u0119c \u017cebym jej nie przeczyta\u0142, no nie? I zdecydowanie polecam j\u0105 ka\u017cdemu programi\u015bcie, kt\u00f3ry chcia\u0142by by\u0107 jak najlepszy w tym, co robi.\u003C\/p\u003E\n\u003Cp\u003EChcia\u0142bym tutaj pokaza\u0107 na konkretnym fragmencie kodu, jak wiele mo\u017ce zmieni\u0107 stosowanie si\u0119 do zasad przedstawionych przez Martina. Na przyk\u0142adzie autoloadera.\u003C\/p\u003E\n\u003Cp\u003ETylko najpierw kr\u00f3tki wst\u0119p, co to w og\u00f3le jest \u201cautoloader\u201d. Ot\u00f3\u017c: przy ka\u017cdym \u017c\u0105daniu do serwera uruchamiana jest nowa instancja interpretera PHP. Aby nie musia\u0142 on \u0142adowa\u0107 wszystkich plik\u00f3w .php obecnych w projekcie (a potrafi\u0105 ich by\u0107 tysi\u0105ce), lecz tylko te, z kt\u00f3rych akurat w tym \u017c\u0105daniu skorzysta, u\u017cywany jest mechanizm auto\u0142adowania. Dzia\u0142a to tak, \u017ce kiedy interpreter PHP trafi na u\u017cycie klasy, kt\u00f3rej nie zna, odpyta o ni\u0105 po kolei autoloadery, kt\u00f3re ma zarejestrowane. Je\u015bli kt\u00f3ry\u015b z nich zwr\u00f3ci true, oznacza to, \u017ce znalaz\u0142 on plik, w kt\u00f3rym dana klasa powinna si\u0119 znajdowa\u0107, i do\u0142\u0105czy\u0142 go. W przeciwnym razie interpreter pyta kolejnego autoloadera w kolejce, a dopiero je\u015bli wszystkie zawiod\u0105 \u2013 wyrzuca fatal error \u201cClass not found\u201d.\u003C\/p\u003E\n\u003Cp\u003ENapisa\u0142em sobie kiedy\u015b ma\u0142\u0105 klas\u0119 autoloadera, a raczej poprzerabia\u0142em jak\u0105\u015b znalezion\u0105 na necie. Wygl\u0105da\u0142a tak:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;?php\n\nclass Autoloader {\n\n    private $namespace;\n\n    private $path;\n\n    private $valid = false;\n\n    public function __construct($namespace, $path = \u0027\u0027) {\n        $this-\u0026gt;namespace = $namespace;\n        $this-\u0026gt;path = $path;\n        $this-\u0026gt;valid = true;\n    }\n\n    public function autoload($className) {\n        \/\/ is this autoloader responsible for that particular class?\n        if (substr($className,0,strlen($this-\u0026gt;namespace)) === $this-\u0026gt;namespace) {\n            $path = $this-\u0026gt;path . str_replace(\u0027\\\\\u0027,\u0027\/\u0027, ltrim( $className, \u0027\\\\\u0027)) . \u0027.php\u0027;\n            if (file_exists($path)) {\n                require_once($path);\n                return true;\n            } else {\n                \/\/ if not straightforward, maybe try \u0022common\u0022 class files\n                \/\/ eg. \u0022Exceptions\u0022 for \u0022NotFoundException\u0022;\n                $slashPos = strrpos($className,\u0027\\\\\u0027,-1) + 1;\n                $base = substr($className,0,$slashPos);\n                $classPure = substr($className,$slashPos);\n                preg_match_all(\u0027\/(?:^|[A-Z])[a-z]+\/\u0027,$classPure,$matches);\n                $path = $this-\u0026gt;path . str_replace(\u0027\\\\\u0027,\u0027\/\u0027, ltrim( $base . end($matches[0]) . \u0027s\u0027, \u0027\\\\\u0027)) . \u0027.php\u0027;\n                if (file_exists($path)) {\n                    require_once($path);\n                    return true;\n                } else {\n                    return false; \/\/ damn, maybe other autoloaders will find something\n                }\n            }\n        } else {\n            return false; \/\/ no, let the other autoloaders handle that\n        }\n    }\n\n    public function register() {\n        if ($this-\u0026gt;valid) {\n            spl_autoload_register(array($this, \u0027autoload\u0027));\n            $this-\u0026gt;valid = false; \/\/in order not to register it twice\n        }\n    }\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EPrzyk\u0142adowe u\u017cycie mojego autoloadera wygl\u0105da nast\u0119puj\u0105co:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;?php\n$autoloader = new Autoloader(\u0027Micrus\\\\\u0027, __DIR__ . \u0027\/vendor\/\u0027);\n$autoloader-\u0026gt;register();\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETworzymy nowy autoloader maj\u0105cy obs\u0142ugiwa\u0107 wszystkie klasy w przestrzeni nazw \u201cMicrus\u201d i szukaj\u0105cy ich w katalogu \u201cvendor\u201d, gdzie klasy s\u0105 umieszczone w podfolderach zgodnie ze swoj\u0105 przestrzeni\u0105 nazw. Oznacza to, \u017ce je\u015bli gdzie\u015b w kodzie b\u0119dziemy chcieli stworzy\u0107 nowy obiekt klasy \u003Ccode\u003EMicrus\\Foo\\Bar\\MyClass\u003C\/code\u003E, to powinna si\u0119 ona znajdowa\u0107 w pliku \u003Ccode\u003E\/vendor\/Micrus\/Foo\/Bar\/MyClass.php\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EDo tego dochodzi jeszcze pewien ma\u0142y feature (niezgodny z \u003Ca href=\u0022http:\/\/www.php-fig.org\/psr\/psr-4\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E PSR-4\u003C\/a\u003E). Ot\u00f3\u017c je\u015bli chcemy zgrupowa\u0107 kilka podobnych klas w jednym pliku, mo\u017cemy zrobi\u0107 to w bardzo prosty spos\u00f3b. Mamy na przyk\u0142ad klasy wyj\u0105tk\u00f3w, kt\u00f3re potrafi\u0105 by\u0107 naprawd\u0119 malutkie i czasem niewygodnie jest rozbija\u0107 je na osobne pliki. Nazywamy je wszystkie u\u017cywaj\u0105c \u003Ca href=\u0022http:\/\/pl.wikipedia.org\/wiki\/PascalCase\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E PascalCase\u003C\/a\u003E z \u201cException\u201d jako ostatnim s\u0142owem i umieszczamy w pliku \u003Ccode\u003EExceptions.php\u003C\/code\u003E (z dodatkowym -s). M\u00f3j autoloader obs\u0142u\u017cy taki przypadek.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003E\u0026lt;?php\nnamespace Micrus;\n\nclass ConfigFileException extends \\Exception { }\nclass NotFoundException extends \\Exception { protected $code = 404; }\nclass CacheException extends \\Exception { }\nclass RouteNotFoundException extends \\Exception { protected $code = 404; }\nclass InvalidArgumentException extends \\Exception { }\nclass UnauthorisedException extends \\Exception { protected $code = 403; }\nclass ArgvException extends \\Exception { }\nclass DatabaseException extends \\Exception { }\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EKod autoloadera nie wygl\u0105da \u017ale (a przynajmniej widzia\u0142em gorsze). Ale pierwsze spojrzenie na metod\u0119 \u201cautoload\u201d potrafi przerazi\u0107. Jest okropnie nieczytelna, mimo \u017ce komentarze obja\u015bniaj\u0105 jej dzia\u0142anie. Potrzeba troch\u0119 wysi\u0142ku, \u017ceby dowiedzie\u0107 si\u0119, co konkretnie robi.\u003C\/p\u003E\n\u003Cp\u003EWszyscy ucz\u0105, zeby pisa\u0107 komentarze do kodu. Du\u017co komentarzy. Nawet je\u015bli wydaje ci si\u0119 to bezsensowne, bo przecie\u017c rozumiesz, co napisa\u0142e\u015b, to musisz bra\u0107 pod uwag\u0119, \u017ce je\u015bli kod trafi w r\u0119ce kogo innego, albo i ty sam zajrzysz do niego rok czy dwa p\u00f3\u017aniej, to rozszyfrowanie go mo\u017ce ju\u017c nie by\u0107 takie proste.\u003C\/p\u003E\n\u003Cp\u003EMartin natomiast uczy czego innego. Dobry kod wymaga tylko znikomej liczby komentarzy. Je\u015bli ich potrzebujesz, by zrozumie\u0107, co si\u0119 dzieje, znaczy \u017ce kod jest nieczytelny. No i komentarze s\u0105 w pewnym sensie \u003Cem\u003Eniebezpieczne\u003C\/em\u003E: zapominamy je pisa\u0107, zapominamy je aktualizowa\u0107, boimy si\u0119 je usuwa\u0107, szybko trac\u0105 na wa\u017cno\u015bci...\u003C\/p\u003E\n\u003Cp\u003ESp\u00f3jrzcie na kod autoloadera po serii poprawek:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003E\u0026lt;?php\n\nclass Autoloader\n{\n    private $namespace;\n\n    private $path;\n\n    private $registered = false;\n\n    public function __construct($namespace, $path = \u0027.\u0027)\n    {\n        $this-\u0026gt;namespace = $this-\u0026gt;addEndingSlash($namespace, \u0027\\\\\u0027);\n        $this-\u0026gt;path = $this-\u0026gt;addEndingSlash($path, \u0027\/\u0027);\n    }\n\n    private function addEndingSlash($word, $slash = \u0027\/\u0027)\n    {\n        $lastCharacter = substr($word, -1);\n        return $lastCharacter == $slash ? $word : $word . $slash;\n    }\n\n    public function autoload($className)\n    {\n        if ($this-\u0026gt;isNotResponsibleForClass($className)) {\n            return false;\n        }\n\n        $path = $this-\u0026gt;classNameToFilePath($className);\n        if (file_exists($path)) {\n            require_once($path);\n            return true;\n        }\n\n        $groupName = $this-\u0026gt;classNameToGroupName($className);\n        $path = $this-\u0026gt;classNameToFilePath($groupName);\n        if (file_exists($path)) {\n            require_once($path);\n            return true;\n        }\n\n        return false;\n    }\n\n    private function isNotResponsibleForClass($className)\n    {\n        return substr($className, 0, strlen($this-\u0026gt;namespace)) !== $this-\u0026gt;namespace;\n    }\n\n    private function classNameToFilePath($className)\n    {\n        return $this-\u0026gt;path . str_replace(\u0027\\\\\u0027,\u0027\/\u0027, ltrim( $className, \u0027\\\\\u0027)) . \u0027.php\u0027;\n    }\n\n    private function classNameToGroupName($className)\n    {\n        $slashPos = strrpos($className,\u0027\\\\\u0027,-1) + 1;\n        $base = substr($className,0,$slashPos);\n        $classPure = substr($className,$slashPos);\n        preg_match_all(\u0027\/(?:^|[A-Z])[a-z]+\/\u0027,$classPure,$matches);\n\n        return $base . end($matches[0]) . \u0027s\u0027;\n    }\n\n    public function register()\n    {\n        if ($this-\u0026gt;registered) { return false; }\n        spl_autoload_register(array($this, \u0027autoload\u0027));\n        $this-\u0026gt;registered = true;\n\n        return true;\n    }\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWystarczy zerkn\u0105\u0107 na funkcj\u0119 autoload, \u017ceby wiedzie\u0107, co robi. Ba, nawet nie trzeba zna\u0107 \u017cadnego j\u0119zyka programowania! To\u017c to niemal czysty angielski: \u201cif this is not responsible for class \u2018class name\u2019, return false\u201d. Nie mamy poj\u0119cia \u003Cem\u003Ejak\u003C\/em\u003E funkcja to robi, ale wida\u0107 jak na d\u0142oni \u003Cem\u003Eco\u003C\/em\u003E takiego wykonuje.\u003C\/p\u003E\n\u003Cp\u003E\u003Cem\u003E\u201cJak\u201d\u003C\/em\u003E natomiast znajduje si\u0119 w osobnych, prywatnych metodach. Rozdzielili\u015bmy zatem od siebie r\u00f3\u017cne \u003Cem\u003Ewarstwy abstrakcji\u003C\/em\u003E, kt\u00f3re wcze\u015bniej by\u0142y zlane w jedn\u0105, brzydk\u0105 funkcj\u0119. Bo je\u015bli kto\u015b zajrzy do naszego kodu, to najprawdopodobniej nie b\u0119dzie potrzebowa\u0142 znajomo\u015bci wszystkiego, co tam naskrobali\u015bmy, lecz przyjdzie z jakim\u015b jednym konkretnym zadaniem: \u201cogarn\u0105\u0107 jak mniej wi\u0119cej dzia\u0142a ten autoloader\u201d, \u201czmieni\u0107 format nazwy \u2018zbiorowego pliku\u2019\u201d, \u201czmieni\u0107 kolejno\u015b\u0107 sprawdzania potencjalnych plik\u00f3w\u201d itp. I dlatego rozdzielenie warstw abstrakcji tak bardzo upro\u015bci mu prac\u0119.\u003C\/p\u003E\n\u003Cp\u003ENa pierwszy rzut oka wydawa\u0142oby si\u0119 sensowniejsze stworzenie metody isResponsibleForClass zamiast jej negacji \u2013 isNotResponsibleForClass. Kto normalny pyta\u0142by klas\u0119, czy \u003Cem\u003Enie jest\u003C\/em\u003E za co\u015b odpowiedzialna? Odpowied\u017a \u201ctak, nie jestem\u201d tylko niepotrzebnie by wszystko zagmatwa\u0142a, prawda? No w\u0142a\u015bnie niekoniecznie. U\u017cycie tej metody jest tylko jedno i sprowadza si\u0119 do \u201cje\u015bli nie jeste\u015b za to odpowiedzialna, to daj sobie spok\u00f3j\u201d. Zapisanie tego warunku jako \u003Ccode\u003Eif (!$this-\u0026gt;isResponsibleForClass($className))\u003C\/code\u003E zmniejsza czytelno\u015b\u0107, poniewa\u017c tego wykrzyknika prawie nie wida\u0107. Zawsze zapominamy o wykrzyknikach...\u003C\/p\u003E\n\u003Cp\u003EZanegowanie dopad\u0142o te\u017c zmienn\u0105 \u003Ccode\u003Evalid\u003C\/code\u003E. Zawsze gdy j\u0105 widzia\u0142em, musia\u0142em si\u0119 zastanowi\u0107, po co ona komu. Kiedy niby autoloader staje si\u0119 \u201cinvalid\u201d? A chodzi przecie\u017c o to, \u017ce autoloader mo\u017ce by\u0107 albo \u003Cem\u003Ejeszcze nie zarejestrowany\u003C\/em\u003E, albo \u003Cem\u003Eju\u017c zarejestrowany\u003C\/em\u003E. Czemu wi\u0119c nie zmieni\u0107 nazwy tej w\u0142a\u015bciwo\u015bci na \u003Ccode\u003Eregistered\u003C\/code\u003E? Teraz metoda \u003Ccode\u003Eregister()\u003C\/code\u003E staje si\u0119 bardzo czytelna: \u201cje\u015bli jeste\u015b zarejestrowany, to ju\u017c wi\u0119cej si\u0119 nie rejestruj\u201d.\u003C\/p\u003E\n\u003Cp\u003EBazowy namespace powinien ko\u0144czy\u0107 si\u0119 backslashem, aby unikn\u0105\u0107 takich sytuacji, gdy chcemy na przyk\u0142ad przechwyci\u0107 klasy \u201cJava\/...\u201d, a zgarniemy tak\u017ce i \u201cJavascript\/...\u201d. Dla zachowania jednorodno\u015bci, to samo powinno dotyczy\u0107 drugiego parametru konstruktora (\u015bcie\u017cki do folderu). Ale po co cz\u0142owiekowi, kt\u00f3ry chce u\u017cy\u0107 naszego autoloadera, kaza\u0107 si\u0119 zastanawia\u0107 nad tym, czy wymagamy slasha czy nie? Mo\u017ce lepiej po prostu sprawd\u017amy, czy slash jest na ko\u0144cu parametru, i doklejmy go, je\u015bli nie? Dodanie metody \u003Ccode\u003EaddEndingSlash\u003C\/code\u003E sprawi\u0142o, \u017ce nie tylko sama klasa jest prostsza, ale tak\u017ce i jej u\u017cycie na zewn\u0105trz.\u003C\/p\u003E\n\u003Cp\u003ETym oto sposobem w nowym kodzie jest zdecydowanie mniej zagnie\u017cd\u017ce\u0144, metody s\u0105 kr\u00f3tsze, a ka\u017cda zajmuje si\u0119 dok\u0142adnie jedn\u0105 rzecz\u0105 na jednym poziomie abstrakcji.\u003C\/p\u003E\n\u003Cp\u003EI jak? Kt\u00f3r\u0105 wersj\u0119 wolicie? Kt\u00f3ra nie marnuje czasu programisty pr\u00f3buj\u0105cego j\u0105 zrozumie\u0107?\u003C\/p\u003E\n\u003Cp\u003E\u201cCzysty kod\u201d warto przeczyta\u0107, warto do niego wraca\u0107 i \u2013 przede wszystkim \u2013 warto stosowa\u0107 si\u0119 do zawartych w nim rad.\u003C\/p\u003E","words":1438,"readTime":6,"lang":"pl"}}}}}