├── docs ├── src │ ├── data │ │ └── .gitkeep │ ├── assets │ │ ├── js │ │ │ ├── app.js │ │ │ ├── vendor │ │ │ │ └── .gitkeep │ │ │ ├── lazysizes.js │ │ │ ├── instant.page.js │ │ │ ├── bootstrap.js │ │ │ ├── katex.js │ │ │ ├── alert.js │ │ │ ├── mermaid.js │ │ │ ├── clipboard.js │ │ │ └── highlight.js │ │ ├── fonts │ │ │ └── .gitkeep │ │ ├── images │ │ │ └── .gitkeep │ │ └── scss │ │ │ ├── vendor │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ ├── _tables.scss │ │ │ ├── _mermaid.scss │ │ │ ├── _forms.scss │ │ │ ├── _comments.scss │ │ │ ├── _images.scss │ │ │ ├── _code.scss │ │ │ ├── _syntax.scss │ │ │ ├── _search.scss │ │ │ └── _alerts.scss │ │ │ ├── layouts │ │ │ ├── _footer.scss │ │ │ ├── _posts.scss │ │ │ ├── _pages.scss │ │ │ └── _sidebar.scss │ │ │ ├── app.scss │ │ │ └── common │ │ │ └── _fonts.scss │ ├── static │ │ ├── css │ │ │ └── vendor │ │ │ │ └── .gitkeep │ │ ├── fonts │ │ │ ├── vendor │ │ │ │ ├── .gitkeep │ │ │ │ └── jost │ │ │ │ │ ├── jost-v4-latin-500.woff │ │ │ │ │ ├── jost-v4-latin-500.woff2 │ │ │ │ │ ├── jost-v4-latin-700.woff │ │ │ │ │ ├── jost-v4-latin-700.woff2 │ │ │ │ │ ├── jost-v4-latin-italic.woff │ │ │ │ │ ├── jost-v4-latin-italic.woff2 │ │ │ │ │ ├── jost-v4-latin-regular.woff │ │ │ │ │ ├── jost-v4-latin-500italic.woff │ │ │ │ │ ├── jost-v4-latin-700italic.woff │ │ │ │ │ ├── jost-v4-latin-regular.woff2 │ │ │ │ │ ├── jost-v4-latin-500italic.woff2 │ │ │ │ │ └── jost-v4-latin-700italic.woff2 │ │ │ ├── KaTeX_Main-Bold.ttf │ │ │ ├── KaTeX_Main-Bold.woff │ │ │ ├── KaTeX_AMS-Regular.ttf │ │ │ ├── KaTeX_AMS-Regular.woff │ │ │ ├── KaTeX_AMS-Regular.woff2 │ │ │ ├── KaTeX_Fraktur-Bold.ttf │ │ │ ├── KaTeX_Fraktur-Bold.woff │ │ │ ├── KaTeX_Main-Bold.woff2 │ │ │ ├── KaTeX_Main-Italic.ttf │ │ │ ├── KaTeX_Main-Italic.woff │ │ │ ├── KaTeX_Main-Italic.woff2 │ │ │ ├── KaTeX_Main-Regular.ttf │ │ │ ├── KaTeX_Main-Regular.woff │ │ │ ├── KaTeX_Math-Italic.ttf │ │ │ ├── KaTeX_Math-Italic.woff │ │ │ ├── KaTeX_Math-Italic.woff2 │ │ │ ├── KaTeX_Size1-Regular.ttf │ │ │ ├── KaTeX_Size2-Regular.ttf │ │ │ ├── KaTeX_Size3-Regular.ttf │ │ │ ├── KaTeX_Size4-Regular.ttf │ │ │ ├── KaTeX_Fraktur-Bold.woff2 │ │ │ ├── KaTeX_Fraktur-Regular.ttf │ │ │ ├── KaTeX_Main-BoldItalic.ttf │ │ │ ├── KaTeX_Main-Regular.woff2 │ │ │ ├── KaTeX_Math-BoldItalic.ttf │ │ │ ├── KaTeX_SansSerif-Bold.ttf │ │ │ ├── KaTeX_SansSerif-Bold.woff │ │ │ ├── KaTeX_Script-Regular.ttf │ │ │ ├── KaTeX_Script-Regular.woff │ │ │ ├── KaTeX_Size1-Regular.woff │ │ │ ├── KaTeX_Size1-Regular.woff2 │ │ │ ├── KaTeX_Size2-Regular.woff │ │ │ ├── KaTeX_Size2-Regular.woff2 │ │ │ ├── KaTeX_Size3-Regular.woff │ │ │ ├── KaTeX_Size3-Regular.woff2 │ │ │ ├── KaTeX_Size4-Regular.woff │ │ │ ├── KaTeX_Size4-Regular.woff2 │ │ │ ├── KaTeX_Caligraphic-Bold.ttf │ │ │ ├── KaTeX_Caligraphic-Bold.woff │ │ │ ├── KaTeX_Caligraphic-Bold.woff2 │ │ │ ├── KaTeX_Fraktur-Regular.woff │ │ │ ├── KaTeX_Fraktur-Regular.woff2 │ │ │ ├── KaTeX_Main-BoldItalic.woff │ │ │ ├── KaTeX_Main-BoldItalic.woff2 │ │ │ ├── KaTeX_Math-BoldItalic.woff │ │ │ ├── KaTeX_Math-BoldItalic.woff2 │ │ │ ├── KaTeX_SansSerif-Bold.woff2 │ │ │ ├── KaTeX_SansSerif-Italic.ttf │ │ │ ├── KaTeX_SansSerif-Italic.woff │ │ │ ├── KaTeX_SansSerif-Italic.woff2 │ │ │ ├── KaTeX_SansSerif-Regular.ttf │ │ │ ├── KaTeX_SansSerif-Regular.woff │ │ │ ├── KaTeX_Script-Regular.woff2 │ │ │ ├── KaTeX_Typewriter-Regular.ttf │ │ │ ├── KaTeX_Caligraphic-Regular.ttf │ │ │ ├── KaTeX_Caligraphic-Regular.woff │ │ │ ├── KaTeX_SansSerif-Regular.woff2 │ │ │ ├── KaTeX_Typewriter-Regular.woff │ │ │ ├── KaTeX_Typewriter-Regular.woff2 │ │ │ └── KaTeX_Caligraphic-Regular.woff2 │ │ ├── images │ │ │ └── vendor │ │ │ │ └── .gitkeep │ │ ├── js │ │ │ └── vendor │ │ │ │ └── .gitkeep │ │ ├── CNAME │ │ ├── flow.png │ │ ├── favicon.ico │ │ ├── logo-flow.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── videos │ │ │ ├── flower.mp4 │ │ │ └── flower.webm │ │ ├── apple-touch-icon.png │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── site.webmanifest │ │ ├── flow.svg │ │ └── logo-flow.svg │ ├── layouts │ │ ├── _default │ │ │ ├── _markup │ │ │ │ └── .gitkeep │ │ │ ├── single.html │ │ │ ├── index.js │ │ │ ├── index.json │ │ │ ├── list.html │ │ │ ├── baseof.html │ │ │ └── section.sitemap.xml │ │ ├── partials │ │ │ ├── main │ │ │ │ ├── headline-hash.html │ │ │ │ ├── breadcrumb.html │ │ │ │ ├── blog-meta.html │ │ │ │ ├── edit-page.html │ │ │ │ └── docs-navigation.html │ │ │ ├── sidebar │ │ │ │ ├── docs-toc.html │ │ │ │ └── docs-menu.html │ │ │ ├── head │ │ │ │ ├── script-header.html │ │ │ │ ├── favicons.html │ │ │ │ ├── resource-hints.html │ │ │ │ ├── head.html │ │ │ │ ├── stylesheet.html │ │ │ │ ├── twitter_cards.html │ │ │ │ └── seo.html │ │ │ ├── header │ │ │ │ └── alert.html │ │ │ └── footer │ │ │ │ └── footer.html │ │ ├── robots.txt │ │ ├── index.redirects │ │ ├── 404.html │ │ ├── shortcodes │ │ │ ├── email.html │ │ │ ├── mermaid.html │ │ │ ├── video.html │ │ │ ├── alert.html │ │ │ ├── img-simple.html │ │ │ └── img.html │ │ ├── blog │ │ │ ├── single.html │ │ │ └── list.html │ │ ├── index.headers │ │ ├── contributors │ │ │ └── list.html │ │ ├── docs │ │ │ ├── list.html │ │ │ └── single.html │ │ ├── sitemap.xml │ │ └── rss.xml │ ├── config │ │ ├── next │ │ │ └── config.toml │ │ ├── production │ │ │ └── config.toml │ │ ├── _default │ │ │ ├── languages.toml │ │ │ ├── markup.toml │ │ │ ├── menus │ │ │ │ └── menus.en.toml │ │ │ ├── config.toml │ │ │ └── params.toml │ │ └── postcss.config.js │ ├── i18n │ │ └── en.toml │ ├── images │ │ ├── logo.png │ │ └── favicon.ico │ ├── content │ │ └── en │ │ │ ├── blog │ │ │ ├── say-hello-to-doks │ │ │ │ ├── say-hello-to-doks.png │ │ │ │ └── index.md │ │ │ └── _index.md │ │ │ ├── docs │ │ │ ├── _index.md │ │ │ └── getting-started │ │ │ │ ├── _index.md │ │ │ │ ├── changelog.md │ │ │ │ ├── ip-strategy.md │ │ │ │ ├── async-handler.md │ │ │ │ ├── introduction.md │ │ │ │ ├── license.md │ │ │ │ ├── flow.md │ │ │ │ └── job.md │ │ │ ├── contributors │ │ │ ├── _index.md │ │ │ └── matyo91 │ │ │ │ └── _index.md │ │ │ ├── contact │ │ │ └── index.md │ │ │ ├── _index.md │ │ │ └── privacy-policy │ │ │ └── index.md │ ├── archetypes │ │ ├── default.md │ │ ├── blog.md │ │ └── docs.md │ └── functions │ │ └── hi-from-lambda.js ├── .markdownlintignore ├── .stylelintignore ├── .eslintignore ├── .markdownlint.json ├── babel.config.js ├── theme.toml ├── .stylelintrc.json └── .eslintrc.json ├── tools ├── .gitignore ├── phan │ ├── .gitignore │ ├── composer.json │ ├── castor.php │ └── phan.php ├── phpcbf │ ├── .gitignore │ ├── composer.json │ ├── castor.php │ └── phpcs.xml ├── phpcs │ ├── .gitignore │ ├── composer.json │ ├── castor.php │ └── phpcs.xml ├── phpmd │ ├── .gitignore │ ├── composer.json │ ├── castor.php │ └── phpmd.xml ├── phpstan │ ├── .gitignore │ ├── phpstan.neon │ ├── castor.php │ └── composer.json ├── psalm │ ├── .gitignore │ ├── composer.json │ ├── castor.php │ └── psalm.xml ├── infection │ ├── .gitignore │ ├── castor.php │ ├── infection.json │ ├── composer.json │ └── phpunit.xml.dist ├── editorconfig-fixer │ ├── .gitignore │ ├── composer.json │ ├── castor.php │ └── composer.lock ├── phpunit │ ├── .gitignore │ ├── composer.json │ ├── phpunit.xml │ └── castor.php ├── php-cs-fixer │ ├── .gitignore │ ├── composer.json │ ├── castor.php │ └── .php-cs-fixer.php ├── dev │ ├── docker-compose.yml │ ├── castor.php │ └── Dockerfile ├── docs-serve │ └── castor.php └── castor.php ├── .github ├── FUNDING.yml └── workflows │ └── docs-deploy.yaml ├── .gitignore ├── src ├── ExceptionInterface.php ├── Bridge │ └── Symfony │ │ ├── FlowBundle.php │ │ ├── Resources │ │ └── config │ │ │ └── services.php │ │ └── DependencyInjection │ │ ├── FlowExtension.php │ │ └── Configuration.php ├── Exception │ ├── LogicException.php │ └── RuntimeException.php ├── Ip.php ├── JobInterface.php ├── Attribute │ └── AsJob.php ├── IpStrategyInterface.php ├── AsyncHandlerInterface.php ├── Event │ ├── PopEvent.php │ ├── PushEvent.php │ ├── PullEvent.php │ ├── PoolEvent.php │ └── AsyncEvent.php ├── Job │ ├── ClosureJob.php │ └── YJob.php ├── Driver │ └── DriverTrait.php ├── Flow │ ├── FlowDecorator.php │ ├── YFlow.php │ ├── LambdaFlow.php │ └── TransportFlow.php ├── IpPool.php ├── AsyncHandler │ ├── AsyncHandler.php │ ├── DeferAsyncHandler.php │ └── BatchAsyncHandler.php ├── IpStrategy │ ├── StackIpStrategy.php │ └── LinearIpStrategy.php ├── Event.php ├── DriverInterface.php └── FlowInterface.php ├── examples ├── Model │ ├── DataD.php │ ├── DataC.php │ ├── DataB.php │ ├── DataA.php │ └── YFlowData.php ├── Stamp │ └── DoctrineIpTransportIdStamp.php ├── Transport │ ├── Sender │ │ └── CollectionSender.php │ ├── Receiver │ │ └── CollectionReceiver.php │ ├── CollectionTransport.php │ └── Client.php └── client.php ├── .editorconfig ├── tests ├── Job │ ├── ClosureJobTest.php │ └── YJobTest.php ├── Examples │ ├── Stamp │ │ └── DoctrineIpTransportIdStampTest.php │ └── Transport │ │ ├── Sender │ │ └── CollectionSenderTest.php │ │ └── DoctrineIpTransportTest.php ├── Driver │ ├── AmpDriverTest.php │ ├── FiberDriverTest.php │ ├── ReactDriverTest.php │ ├── SpatieDriverTest.php │ └── SwooleDriverTest.php ├── AsyncHandler │ ├── AsyncHandlerTest.php │ ├── DeferAsyncHandlerTest.php │ └── BatchAsyncHandlerTest.php ├── IpStrategy │ ├── StackIpStrategyTest.php │ ├── LinearIpStrategyTest.php │ └── MaxIpStrategyTest.php └── Flow │ ├── FlowTrait.php │ └── YFlowTest.php ├── VERSIONING.md ├── LICENSE ├── Makefile ├── README.md └── CONTRIBUTING.md /docs/src/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/assets/js/app.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/assets/fonts/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/assets/images/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/assets/js/vendor/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/assets/scss/vendor/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/static/css/vendor/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/static/images/vendor/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/static/js/vendor/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | /.castor.stub.php 2 | -------------------------------------------------------------------------------- /tools/phan/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /tools/phpcbf/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /tools/phpcs/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /tools/phpmd/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /tools/phpstan/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /tools/psalm/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /docs/src/layouts/_default/_markup/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/static/CNAME: -------------------------------------------------------------------------------- 1 | flow.darkwood.com 2 | -------------------------------------------------------------------------------- /tools/infection/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /tools/editorconfig-fixer/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /docs/src/assets/js/lazysizes.js: -------------------------------------------------------------------------------- 1 | import 'lazysizes'; 2 | -------------------------------------------------------------------------------- /docs/src/config/next/config.toml: -------------------------------------------------------------------------------- 1 | canonifyURLs = false 2 | -------------------------------------------------------------------------------- /tools/phpunit/.gitignore: -------------------------------------------------------------------------------- 1 | /.phpunit.cache 2 | /vendor/ 3 | -------------------------------------------------------------------------------- /docs/src/assets/js/instant.page.js: -------------------------------------------------------------------------------- 1 | import 'instant.page'; 2 | -------------------------------------------------------------------------------- /docs/src/config/production/config.toml: -------------------------------------------------------------------------------- 1 | canonifyURLs = false 2 | -------------------------------------------------------------------------------- /docs/src/i18n/en.toml: -------------------------------------------------------------------------------- 1 | [get-started] 2 | other = "Get Started" -------------------------------------------------------------------------------- /docs/.markdownlintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | CHANGELOG.md 3 | README.md -------------------------------------------------------------------------------- /tools/php-cs-fixer/.gitignore: -------------------------------------------------------------------------------- 1 | /.php-cs-fixer.cache 2 | /vendor/ 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [matyo91] 4 | -------------------------------------------------------------------------------- /docs/src/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/images/logo.png -------------------------------------------------------------------------------- /docs/src/static/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/flow.png -------------------------------------------------------------------------------- /docs/.stylelintignore: -------------------------------------------------------------------------------- 1 | src/assets/scss/components/_syntax.scss 2 | src/assets/scss/vendor 3 | node_modules -------------------------------------------------------------------------------- /docs/src/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/images/favicon.ico -------------------------------------------------------------------------------- /docs/src/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/favicon.ico -------------------------------------------------------------------------------- /docs/.eslintignore: -------------------------------------------------------------------------------- 1 | src/assets/js/index.js 2 | src/assets/js/katex.js 3 | src/assets/js/vendor 4 | node_modules -------------------------------------------------------------------------------- /docs/src/assets/scss/components/_tables.scss: -------------------------------------------------------------------------------- 1 | table { 2 | @extend .table; 3 | 4 | margin: 3rem 0; 5 | } 6 | -------------------------------------------------------------------------------- /docs/src/static/logo-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/logo-flow.png -------------------------------------------------------------------------------- /docs/src/static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/favicon-16x16.png -------------------------------------------------------------------------------- /docs/src/static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/favicon-32x32.png -------------------------------------------------------------------------------- /docs/src/static/videos/flower.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/videos/flower.mp4 -------------------------------------------------------------------------------- /docs/src/static/videos/flower.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/videos/flower.webm -------------------------------------------------------------------------------- /docs/src/static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/apple-touch-icon.png -------------------------------------------------------------------------------- /tools/php-cs-fixer/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "friendsofphp/php-cs-fixer": "^3.61" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /docs/src/assets/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap/dist/js/bootstrap.bundle.min.js' 2 | // import 'bootstrap/dist/js/bootstrap.min.js' 3 | -------------------------------------------------------------------------------- /docs/src/static/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/src/static/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-Bold.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-Bold.woff -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Docs 2 | /docs/node_modules/ 3 | /docs/src/public/ 4 | /docs/src/resources/ 5 | 6 | # PHP 7 | /composer.lock 8 | /vendor/ 9 | -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_AMS-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_AMS-Regular.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_AMS-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_AMS-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_AMS-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_AMS-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Fraktur-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Fraktur-Bold.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Fraktur-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Fraktur-Bold.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-Bold.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-Italic.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-Italic.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-Italic.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-Regular.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Math-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Math-Italic.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Math-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Math-Italic.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Math-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Math-Italic.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size1-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size1-Regular.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size2-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size2-Regular.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size3-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size3-Regular.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size4-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size4-Regular.ttf -------------------------------------------------------------------------------- /tools/editorconfig-fixer/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "tomasvotruba/editorconfig-fixer": "^0.1.2" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Fraktur-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Fraktur-Bold.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Fraktur-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Fraktur-Regular.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-BoldItalic.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Math-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Math-BoldItalic.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_SansSerif-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_SansSerif-Bold.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_SansSerif-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_SansSerif-Bold.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Script-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Script-Regular.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Script-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Script-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size1-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size1-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size1-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size1-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size2-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size2-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size2-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size2-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size3-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size3-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size3-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size3-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size4-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size4-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Size4-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Size4-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Caligraphic-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Caligraphic-Bold.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Caligraphic-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Caligraphic-Bold.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Caligraphic-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Caligraphic-Bold.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Fraktur-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Fraktur-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Fraktur-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Fraktur-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-BoldItalic.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Main-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Main-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Math-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Math-BoldItalic.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Math-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Math-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_SansSerif-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_SansSerif-Bold.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_SansSerif-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_SansSerif-Italic.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_SansSerif-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_SansSerif-Italic.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_SansSerif-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_SansSerif-Italic.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_SansSerif-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_SansSerif-Regular.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_SansSerif-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_SansSerif-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Script-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Script-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Typewriter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Typewriter-Regular.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Caligraphic-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Caligraphic-Regular.ttf -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Caligraphic-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Caligraphic-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_SansSerif-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_SansSerif-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Typewriter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Typewriter-Regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Typewriter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Typewriter-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/assets/scss/components/_mermaid.scss: -------------------------------------------------------------------------------- 1 | .mermaid { 2 | margin: 1.5rem 0; 3 | padding: 1.5rem; 4 | } 5 | 6 | .mermaid svg { 7 | height: auto; 8 | } 9 | -------------------------------------------------------------------------------- /docs/src/static/fonts/KaTeX_Caligraphic-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/KaTeX_Caligraphic-Regular.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-500.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-500.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-500.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-700.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-700.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-italic.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-italic.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-regular.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-500italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-500italic.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-700italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-700italic.woff -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-regular.woff2 -------------------------------------------------------------------------------- /tools/phpstan/phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 6 3 | bootstrapFiles: 4 | - vendor/autoload.php 5 | paths: 6 | - ../../examples 7 | - ../../src 8 | - ../../tests 9 | -------------------------------------------------------------------------------- /docs/src/content/en/blog/say-hello-to-doks/say-hello-to-doks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/content/en/blog/say-hello-to-doks/say-hello-to-doks.png -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-500italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-500italic.woff2 -------------------------------------------------------------------------------- /docs/src/static/fonts/vendor/jost/jost-v4-latin-700italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkwood-com/flow/HEAD/docs/src/static/fonts/vendor/jost/jost-v4-latin-700italic.woff2 -------------------------------------------------------------------------------- /docs/src/layouts/partials/main/headline-hash.html: -------------------------------------------------------------------------------- 1 | {{ . | replaceRE "()" `${1} ${3}` | safeHTML }} -------------------------------------------------------------------------------- /src/ExceptionInterface.php: -------------------------------------------------------------------------------- 1 | 3 |

On this page

4 | {{ .TableOfContents }} 5 | 6 | {{ end -}} -------------------------------------------------------------------------------- /docs/src/layouts/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | {{ if eq (hugo.Environment) "production" -}} 3 | Allow: / 4 | {{ else -}} 5 | Disallow: / 6 | {{ end }} 7 | Sitemap: {{ "sitemap.xml" | absURL -}} 8 | -------------------------------------------------------------------------------- /docs/src/content/en/blog/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Blog" 3 | description: "The Flow Blog." 4 | date: 2020-10-06T08:49:55+00:00 5 | lastmod: 2020-10-06T08:49:55+00:00 6 | draft: false 7 | images: [] 8 | --- 9 | -------------------------------------------------------------------------------- /examples/Model/DataD.php: -------------------------------------------------------------------------------- 1 | {{ $darkModeInit.Content | safeJS }} 4 | {{ end -}} -------------------------------------------------------------------------------- /docs/src/layouts/partials/main/breadcrumb.html: -------------------------------------------------------------------------------- 1 | {{ with .Parent -}} 2 | {{ partial "main/breadcrumb.html" . -}} 3 | 4 | {{ end -}} -------------------------------------------------------------------------------- /docs/.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "Hyas rules", 3 | 4 | "default": true, 5 | "line_length": false, 6 | "no-inline-html": false, 7 | "no-trailing-punctuation": false, 8 | "no-duplicate-heading": false, 9 | "no-bare-urls": false 10 | } -------------------------------------------------------------------------------- /examples/Model/DataA.php: -------------------------------------------------------------------------------- 1 | }} 11 | -------------------------------------------------------------------------------- /docs/src/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 |
5 |

{{ .Title }}

6 | {{ .Content }} 7 |
8 |
9 |
10 | {{ end }} 11 | -------------------------------------------------------------------------------- /docs/src/static/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"Flow","short_name":"Flow","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#fff","background_color":"#fff","display":"standalone"} -------------------------------------------------------------------------------- /docs/src/layouts/_default/index.js: -------------------------------------------------------------------------------- 1 | var docs = [ 2 | {{ range $index, $page := (where .Site.Pages "Section" "docs") -}} 3 | { 4 | id: {{ $index }}, 5 | title: "{{ .Title }}", 6 | description: "{{ .Params.description }}", 7 | href: "{{ .URL }}" 8 | }, 9 | {{ end -}} 10 | ]; -------------------------------------------------------------------------------- /src/Exception/LogicException.php: -------------------------------------------------------------------------------- 1 | { 2 | callback (null, { 3 | statusCode: 200, 4 | headers: { 5 | 'Content-Type': 'application/json', 6 | }, 7 | body: JSON.stringify({ 8 | message: 'Hi from Lambda.', 9 | }), 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /docs/src/content/en/contributors/matyo91/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Mathieu Ledru" 3 | description: "Creator of Darkwood." 4 | date: 2020-10-06T08:50:45+00:00 5 | lastmod: 2020-10-06T08:50:45+00:00 6 | draft: false 7 | images: [] 8 | --- 9 | 10 | Creator of Darkwood. 11 | 12 | [@matyo91](https://twitter.com/matyo91) 13 | -------------------------------------------------------------------------------- /src/JobInterface.php: -------------------------------------------------------------------------------- 1 | result; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/src/layouts/404.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 |
5 |

Page not found :(

6 |

The page you are looking for doesn't exist or has been moved.

7 |
8 |
9 |
10 | {{ end }} -------------------------------------------------------------------------------- /docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | targets: { 7 | browsers: [ 8 | // Best practice: https://github.com/babel/babel/issues/7789 9 | '>=1%', 10 | 'not ie 11', 11 | 'not op_mini all' 12 | ] 13 | } 14 | } 15 | ] 16 | ] 17 | }; -------------------------------------------------------------------------------- /docs/src/layouts/shortcodes/email.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/layouts/shortcodes/mermaid.html: -------------------------------------------------------------------------------- 1 | {{ if .Page.Params.mermaid -}} 2 |
3 | {{ $data := replaceRE "(^\\s+```)" "" .Inner -}} 4 | {{ replaceRE "(```\\s+$)" "" $data -}} 5 |
6 | {{ else -}} 7 | {{ errorf "Failed to process mermaid shortcode: %s. Set mermaid to true in page front matter." .Position }} 8 | {{ end -}} 9 | -------------------------------------------------------------------------------- /src/Attribute/AsJob.php: -------------------------------------------------------------------------------- 1 | }} 14 | -------------------------------------------------------------------------------- /docs/src/archetypes/docs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | description: "" 4 | lead: "" 5 | date: {{ .Date }} 6 | lastmod: {{ .Date }} 7 | draft: true 8 | images: [] 9 | menu: 10 | docs: 11 | parent: "" 12 | weight: 999 13 | toc: true 14 | --- 15 | 16 | {{< img src="{{ .Name | urlize }}.jpg" alt="{{ replace .Name "-" " " | title }}" caption="{{ replace .Name "-" " " | title }}" >}} 17 | -------------------------------------------------------------------------------- /docs/src/assets/scss/layouts/_footer.scss: -------------------------------------------------------------------------------- 1 | .footer { 2 | border-top: 1px solid $gray-200; 3 | padding-top: 1.125rem; 4 | padding-bottom: 1.125rem; 5 | } 6 | 7 | .footer ul { 8 | margin-bottom: 0; 9 | } 10 | 11 | .footer li { 12 | font-size: $font-size-sm; 13 | margin-bottom: 0; 14 | } 15 | 16 | @include media-breakpoint-up(md) { 17 | .footer li { 18 | font-size: $font-size-base; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docs/src/layouts/_default/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 | {{ range .Paginator.Pages }} 5 | 9 | {{ end }} 10 | {{ template "_internal/pagination.html" . }} 11 |
12 |
13 | {{ end }} -------------------------------------------------------------------------------- /docs/src/assets/js/alert.js: -------------------------------------------------------------------------------- 1 | var announcement = document.getElementById('announcement'); 2 | 3 | if (announcement !== null) { 4 | 5 | if (localStorage.getItem('announcement') === null ) { 6 | 7 | announcement.classList.remove('d-none'); 8 | 9 | } 10 | 11 | announcement.addEventListener('closed.bs.alert', () => { 12 | 13 | localStorage.setItem('announcement', 'closed'); 14 | 15 | }); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/layouts/partials/main/blog-meta.html: -------------------------------------------------------------------------------- 1 |

Posted {{ .PublishDate.Format "January 2, 2006" }} by {{ if .Params.contributors -}}{{ range $index, $contributor := .Params.contributors }}{{ if gt $index 0 }} and {{ end }}{{ . }}{{ end -}}{{ end -}} ‐ {{ .ReadingTime -}} min read

-------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true # https://editorconfig.org 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.{php,html,twig}] 10 | indent_style = space 11 | indent_size = 4 12 | 13 | [*.md] 14 | max_line_length = 80 15 | indent_style = space 16 | indent_size = 4 17 | trim_trailing_whitespace = false 18 | 19 | [{*.yml,*.yaml}] 20 | indent_style = space 21 | -------------------------------------------------------------------------------- /tools/dev/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | php: 3 | image: flow-php 4 | build: 5 | context: . 6 | target: php 7 | volumes: 8 | - ../..:/flow 9 | mysql: 10 | image: mysql:8.1 11 | environment: 12 | - MYSQL_ROOT_PASSWORD=root 13 | - MYSQL_DATABASE=flow 14 | - MYSQL_USER=flow 15 | - MYSQL_PASSWORD=flow 16 | -------------------------------------------------------------------------------- /tools/phan/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "phan/phan": "^5.4.2", 4 | "phpunit/phpunit": "^10.3" 5 | }, 6 | "autoload": { 7 | "psr-4": { 8 | "Flow\\": "../../src" 9 | } 10 | }, 11 | "autoload-dev": { 12 | "psr-4": { 13 | "Flow\\Examples\\": "../../examples", 14 | "Flow\\Test\\": "../../tests" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Bridge/Symfony/DependencyInjection/FlowExtension.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 18 | } 19 | -------------------------------------------------------------------------------- /tools/phpmd/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "phpmd/phpmd": "^2.13.0", 4 | "phpunit/phpunit": "^10.3" 5 | }, 6 | "autoload": { 7 | "psr-4": { 8 | "Flow\\": "../../src" 9 | } 10 | }, 11 | "autoload-dev": { 12 | "psr-4": { 13 | "Flow\\Examples\\": "../../examples", 14 | "Flow\\Test\\": "../../tests" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tools/psalm/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "vimeo/psalm": "^5.15.0", 4 | "phpunit/phpunit": "^10.3" 5 | }, 6 | "autoload": { 7 | "psr-4": { 8 | "Flow\\": "../../src" 9 | } 10 | }, 11 | "autoload-dev": { 12 | "psr-4": { 13 | "Flow\\Examples\\": "../../examples", 14 | "Flow\\Test\\": "../../tests" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/layouts/blog/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |

3 |
4 |
5 |
6 |

{{ .Title }}

7 | {{ partial "main/blog-meta.html" . }} 8 |
9 |

{{ .Params.lead | safeHTML }}

10 | {{ .Content }} 11 |
12 |
13 |
14 | {{ end }} -------------------------------------------------------------------------------- /src/IpStrategyInterface.php: -------------------------------------------------------------------------------- 1 | $event 17 | */ 18 | public function pool(PoolEvent $event): void; 19 | } 20 | -------------------------------------------------------------------------------- /tests/Job/ClosureJobTest.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 18 | } 19 | -------------------------------------------------------------------------------- /tools/psalm/castor.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 18 | } 19 | -------------------------------------------------------------------------------- /docs/src/config/_default/languages.toml: -------------------------------------------------------------------------------- 1 | [en] 2 | languageName = "English" 3 | contentDir = "content/en" 4 | weight = 10 5 | [en.params] 6 | languageISO = "EN" 7 | 8 | [de] 9 | languageName = "German" 10 | contentDir = "content/de" 11 | weight = 15 12 | [de.params] 13 | languageISO = "DE" 14 | 15 | [nl] 16 | languageName = "Nederlands" 17 | contentDir = "content/nl" 18 | weight = 20 19 | [nl.params] 20 | languageISO = "NL" 21 | -------------------------------------------------------------------------------- /tools/dev/castor.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 19 | } 20 | -------------------------------------------------------------------------------- /tools/infection/castor.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 18 | } 19 | -------------------------------------------------------------------------------- /tools/phpmd/castor.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 18 | } 19 | -------------------------------------------------------------------------------- /docs/src/layouts/partials/head/favicons.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/src/layouts/partials/main/edit-page.html: -------------------------------------------------------------------------------- 1 |

Edit this page on GitHub

2 | -------------------------------------------------------------------------------- /tools/phpcbf/castor.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 18 | } 19 | -------------------------------------------------------------------------------- /tools/phpcbf/phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ../../examples 4 | ../../src 5 | ../../tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | error 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tools/phpcs/phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ../../examples 4 | ../../src 5 | ../../tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | error 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/src/layouts/shortcodes/video.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ with .Get "webm-src" -}} 4 | 5 | {{ end -}} 6 | {{ with .Get "mp4-src" -}} 7 | 8 | {{ end -}} 9 | Sorry, your browser doesn't support embedded videos. 10 | 11 |
12 | -------------------------------------------------------------------------------- /docs/src/assets/js/mermaid.js: -------------------------------------------------------------------------------- 1 | import mermaid from 'mermaid/dist/mermaid'; 2 | 3 | var config = { 4 | theme: 'default', 5 | fontFamily: '"Jost", -apple-system, blinkmacsystemfont, "Segoe UI", roboto, "Helvetica Neue", arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";', 6 | }; 7 | 8 | document.addEventListener('DOMContentLoaded', () => { 9 | mermaid.initialize(config); 10 | mermaid.init(undefined, '.language-mermaid'); 11 | }); 12 | -------------------------------------------------------------------------------- /docs/src/layouts/shortcodes/alert.html: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /tools/phpstan/castor.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 18 | } 19 | -------------------------------------------------------------------------------- /src/Bridge/Symfony/DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | getId()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/content/en/docs/getting-started/changelog.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Changelog" 3 | description: "Changelog." 4 | lead: "Changelog." 5 | date: 2020-10-13T15:21:01+02:00 6 | lastmod: 2020-10-13T15:21:01+02:00 7 | draft: false 8 | images: [] 9 | menu: 10 | docs: 11 | parent: "getting-started" 12 | weight: 60 13 | toc: true 14 | --- 15 | 16 | # Changelog 17 | 18 | Changelog can be found [https://github.com/darkwood-com/flow/blob/1.x/CHANGELOG.md](https://github.com/darkwood-com/flow/blob/1.x/CHANGELOG.md) 19 | -------------------------------------------------------------------------------- /docs/src/layouts/partials/header/alert.html: -------------------------------------------------------------------------------- 1 | {{ if .Site.Params.alertDismissable -}} 2 | 6 | {{ else -}} 7 | 10 | {{ end -}} 11 | -------------------------------------------------------------------------------- /tests/Driver/AmpDriverTest.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class AmpDriverTest extends DriverTestCase 17 | { 18 | /** 19 | * @return DriverInterface 20 | */ 21 | protected function createDriver(): DriverInterface 22 | { 23 | return new AmpDriver(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tools/editorconfig-fixer/castor.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 18 | } 19 | -------------------------------------------------------------------------------- /tests/Driver/FiberDriverTest.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class FiberDriverTest extends DriverTestCase 17 | { 18 | /** 19 | * @return DriverInterface 20 | */ 21 | protected function createDriver(): DriverInterface 22 | { 23 | return new FiberDriver(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Driver/ReactDriverTest.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class ReactDriverTest extends DriverTestCase 17 | { 18 | /** 19 | * @return DriverInterface 20 | */ 21 | protected function createDriver(): DriverInterface 22 | { 23 | return new ReactDriver(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tools/docs-serve/castor.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 19 | } 20 | -------------------------------------------------------------------------------- /tests/Driver/SpatieDriverTest.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class SpatieDriverTest extends DriverTestCase 17 | { 18 | /** 19 | * @return DriverInterface 20 | */ 21 | protected function createDriver(): DriverInterface 22 | { 23 | return new SpatieDriver(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Driver/SwooleDriverTest.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class SwooleDriverTest extends DriverTestCase 17 | { 18 | /** 19 | * @return DriverInterface 20 | */ 21 | protected function createDriver(): DriverInterface 22 | { 23 | return new SwooleDriver(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docs/src/content/en/blog/say-hello-to-doks/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Say hello to Doks 👋" 3 | description: "Introducing Doks, a Hugo theme helping you build modern documentation websites that are secure, fast, and SEO-ready — by default." 4 | lead: "Introducing Doks, a Hugo theme helping you build modern documentation websites that are secure, fast, and SEO-ready — by default." 5 | date: 2020-11-04T09:19:42+01:00 6 | lastmod: 2020-11-04T09:19:42+01:00 7 | draft: false 8 | weight: 50 9 | images: ["say-hello-to-doks.png"] 10 | contributors: ["Henk Verlinde"] 11 | --- 12 | -------------------------------------------------------------------------------- /docs/src/static/flow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/static/logo-flow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/infection/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "infection/infection": "^0.27", 4 | "phpunit/phpunit": "^10.3" 5 | }, 6 | "autoload": { 7 | "psr-4": { 8 | "Flow\\": "../../src" 9 | } 10 | }, 11 | "autoload-dev": { 12 | "psr-4": { 13 | "Flow\\Examples\\": "../../examples", 14 | "Flow\\Test\\": "../../tests" 15 | } 16 | }, 17 | "config": { 18 | "allow-plugins": { 19 | "infection/extension-installer": true 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Job/YJobTest.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ if .Site.Params.options.kaTex -}} 4 | 5 | 6 | {{ end -}} -------------------------------------------------------------------------------- /docs/src/assets/scss/layouts/_posts.scss: -------------------------------------------------------------------------------- 1 | .home .card, 2 | .contributors.list .card, 3 | .blog.list .card { 4 | margin-top: 2rem; 5 | margin-bottom: 2rem; 6 | transition: transform 0.3s; 7 | } 8 | 9 | .home .card:hover, 10 | .contributors.list .card:hover, 11 | .blog.list .card:hover { 12 | transform: scale(1.025); 13 | } 14 | 15 | .home .card-body, 16 | .contributors.list .card-body, 17 | .blog.list .card-body { 18 | padding: 0 2rem 1rem; 19 | } 20 | 21 | .blog-header { 22 | text-align: center; 23 | margin-bottom: 2rem; 24 | } 25 | 26 | .blog-footer { 27 | text-align: center; 28 | } 29 | -------------------------------------------------------------------------------- /examples/Stamp/DoctrineIpTransportIdStamp.php: -------------------------------------------------------------------------------- 1 | id = $id; 19 | } 20 | 21 | public function getId(): string 22 | { 23 | return $this->id; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/AsyncHandlerInterface.php: -------------------------------------------------------------------------------- 1 | $event 18 | */ 19 | public function async(AsyncEvent $event): void; 20 | 21 | /** 22 | * @param PoolEvent $event 23 | */ 24 | public function pool(PoolEvent $event): void; 25 | } 26 | -------------------------------------------------------------------------------- /src/Event/PopEvent.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | private Ip $ip; 19 | 20 | /** 21 | * @param Ip $ip 22 | */ 23 | public function __construct(Ip $ip) 24 | { 25 | $this->ip = $ip; 26 | } 27 | 28 | /** 29 | * @return Ip 30 | */ 31 | public function getIp(): Ip 32 | { 33 | return $this->ip; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Event/PushEvent.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | private Ip $ip; 19 | 20 | /** 21 | * @param Ip $ip 22 | */ 23 | public function __construct(Ip $ip) 24 | { 25 | $this->ip = $ip; 26 | } 27 | 28 | /** 29 | * @return Ip 30 | */ 31 | public function getIp(): Ip 32 | { 33 | return $this->ip; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Job/ClosureJob.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class ClosureJob implements JobInterface 17 | { 18 | /** 19 | * @param Closure(TArgs): TReturn|JobInterface $job 20 | */ 21 | public function __construct(private Closure|JobInterface $job) {} 22 | 23 | public function __invoke($data): mixed 24 | { 25 | $job = $this->job; 26 | 27 | return $job($data); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/src/layouts/index.headers: -------------------------------------------------------------------------------- 1 | /* 2 | Strict-Transport-Security: max-age=31536000; includeSubDomains; preload 3 | X-Content-Type-Options: nosniff 4 | X-XSS-Protection: 1; mode=block 5 | Content-Security-Policy: default-src 'self'; frame-ancestors https://jamstackthemes.dev; manifest-src 'self'; connect-src 'self'; font-src 'self'; img-src 'self' data:; script-src 'self' 'sha512-RBYr6Ld4w1yVqaACrgrBLQfPgGhj/1jyacA74WxJ1KM6KVcSWymwrdDwb3HDcdpwiNJ5yssot1He0U9vXoQVlg=='; style-src 'self' 'unsafe-inline' 6 | X-Frame-Options: SAMEORIGIN 7 | Referrer-Policy: strict-origin 8 | Feature-Policy: geolocation 'self' 9 | Cache-Control: public, max-age=31536000 -------------------------------------------------------------------------------- /docs/src/layouts/partials/head/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ block "head/resource-hints" . }}{{ partial "head/resource-hints.html" . }}{{ end }} 6 | {{/* block "head/script-header" . }}{{ partial "head/script-header.html" . }}{{ end */}} 7 | {{ block "head/stylesheet" . }}{{ partial "head/stylesheet.html" . }}{{ end }} 8 | {{ block "head/seo" . }}{{ partial "head/seo.html" . }}{{ end }} 9 | {{ block "head/favicons" . }}{{ partial "head/favicons.html" . }}{{ end }} 10 | -------------------------------------------------------------------------------- /docs/src/assets/scss/components/_comments.scss: -------------------------------------------------------------------------------- 1 | .comment-list { 2 | @extend .list-unstyled; 3 | } 4 | 5 | .comment-list ol { 6 | list-style: none; 7 | } 8 | 9 | .comment-form p { 10 | @extend .form-group !optional; 11 | } 12 | 13 | .comment-form input[type="text"], 14 | .comment-form input[type="email"], 15 | .comment-form input[type="url"], 16 | .comment-form textarea { 17 | @extend .form-control; 18 | } 19 | 20 | .comment-form input[type="submit"] { 21 | @extend .btn; 22 | @extend .btn-secondary; 23 | } 24 | 25 | blockquote { 26 | margin-bottom: 1rem; 27 | font-size: 1.25rem; 28 | border-left: 3px solid $gray-300; 29 | padding-left: 1rem; 30 | } 31 | -------------------------------------------------------------------------------- /tools/castor.php: -------------------------------------------------------------------------------- 1 | $dispatchers 17 | */ 18 | public function countIps(array $dispatchers): int 19 | { 20 | $count = 0; 21 | foreach ($dispatchers as $dispatcher) { 22 | $count += count($dispatcher->dispatch(new PoolEvent(), Event::POOL)->getIps()); 23 | } 24 | 25 | return $count; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/src/config/_default/markup.toml: -------------------------------------------------------------------------------- 1 | defaultMarkdownHandler = "goldmark" 2 | 3 | [goldmark] 4 | [goldmark.extensions] 5 | linkify = false 6 | [goldmark.parser] 7 | autoHeadingID = true 8 | autoHeadingIDType = "github" 9 | [goldmark.parser.attribute] 10 | block = true 11 | title = true 12 | [goldmark.renderer] 13 | unsafe = true 14 | 15 | [highlight] 16 | codeFences = true 17 | guessSyntax = true 18 | hl_Lines = "" 19 | lineNoStart = 1 20 | lineNos = false 21 | lineNumbersInTable = true 22 | noClasses = true 23 | style = "igor" 24 | tabWidth = 4 25 | 26 | [tableOfContents] 27 | endLevel = 3 28 | ordered = false 29 | startLevel = 2 30 | -------------------------------------------------------------------------------- /docs/src/layouts/partials/footer/footer.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
    6 |
  • {{ .Site.Params.footer | safeHTML }}
  • 7 |
8 |
9 |
10 |
    11 | {{ range .Site.Menus.footer -}} 12 |
  • {{ .Name }}
  • 13 | {{ end -}} 14 |
15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /docs/src/layouts/shortcodes/img-simple.html: -------------------------------------------------------------------------------- 1 | {{ $image := .Page.Resources.GetMatch (printf "*%s*" (.Get "src")) -}} 2 | {{ $lqip := $image.Resize $.Site.Params.lqipWidth -}} 3 | {{ if eq .Site.Params.options.lazySizes true -}} 4 | 5 | {{ else -}} 6 | 7 | {{ end -}} -------------------------------------------------------------------------------- /examples/Transport/Sender/CollectionSender.php: -------------------------------------------------------------------------------- 1 | $senders 14 | */ 15 | public function __construct(private iterable $senders) {} 16 | 17 | public function send(Envelope $envelope): Envelope 18 | { 19 | foreach ($this->senders as $sender) { 20 | $sender->send($envelope); 21 | } 22 | 23 | return $envelope; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tools/php-cs-fixer/castor.php: -------------------------------------------------------------------------------- 1 | getExitCode(); 24 | } 25 | -------------------------------------------------------------------------------- /docs/src/layouts/partials/main/docs-navigation.html: -------------------------------------------------------------------------------- 1 | {{ if or .Prev .Next -}} 2 |
3 | 4 | {{ $pages := where site.RegularPages "Section" .Section -}} 5 | {{ with $pages.Next . -}} 6 | 7 |
8 |
9 | ← {{ .Title }} 10 |
11 |
12 |
13 | {{ end -}} 14 | {{ with $pages.Prev . -}} 15 | 16 |
17 |
18 | {{ .Title }} → 19 |
20 |
21 |
22 | {{ end -}} 23 |
24 | {{ end -}} -------------------------------------------------------------------------------- /docs/theme.toml: -------------------------------------------------------------------------------- 1 | name = "Flow" 2 | license = "MIT" 3 | licenselink = "https://github.com/darkwood-com/flow/blob/1.x/LICENSE" 4 | description = "Assemble your code by adopting asynchronous as native implementation and build with functional programming and monads." 5 | source = "docs" 6 | 7 | homepage = "https://github.com/darkwood-com/flow" 8 | demosite = "https://flow.darkwood.com" 9 | 10 | tags = ["landing page", "documentation", "blog", "minimal", "modern", "customizable", "search", "dark mode", "bootstrap"] 11 | features = ["security aware", "fast by default", "seo-ready", "development tools", "bootstrap framework", "netlify-ready", "full text search", "page layouts", "dark mode"] 12 | 13 | [author] 14 | name = "Mathieu Ledru" 15 | homepage = "https://darkwood.com" 16 | -------------------------------------------------------------------------------- /tools/phpmd/phpmd.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | All default rulesets from PHPMD. 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "rules": { 4 | "no-empty-source": null, 5 | "string-quotes": "double", 6 | "at-rule-no-unknown": [ 7 | true, 8 | { 9 | "ignoreAtRules": [ 10 | "extend", 11 | "at-root", 12 | "debug", 13 | "warn", 14 | "error", 15 | "if", 16 | "else", 17 | "for", 18 | "each", 19 | "while", 20 | "mixin", 21 | "include", 22 | "content", 23 | "return", 24 | "function", 25 | "tailwind", 26 | "apply", 27 | "responsive", 28 | "variants", 29 | "screen" 30 | ] 31 | } 32 | ] 33 | } 34 | } -------------------------------------------------------------------------------- /tools/phpunit/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "php": ">=8.3", 4 | "symfony/event-dispatcher": "^7.0", 5 | "symfony/messenger": "^7.0" 6 | }, 7 | "require-dev": { 8 | "amphp/amp": "^3.0", 9 | "openswoole/ide-helper": "^22.1.5", 10 | "phpunit/phpunit": "^10.3", 11 | "react/async": "^4.3", 12 | "spatie/async": "^1.6", 13 | "symfony/doctrine-messenger": "^7.0", 14 | "symfony/orm-pack": "^2.4" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "Flow\\": "../../src" 19 | } 20 | }, 21 | "autoload-dev": { 22 | "psr-4": { 23 | "Flow\\Examples\\": "../../examples", 24 | "Flow\\Test\\": "../../tests" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/src/layouts/contributors/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 |
5 |

{{ .Title }}

6 |
{{ .Content }}
7 |
8 | {{ range .Data.Pages -}} 9 |
10 |
11 |

{{ .Params.title }}

12 | {{ if eq .Section "blog" -}} 13 |

{{ .Params.lead | safeHTML }}

14 | {{ partial "main/blog-meta.html" . -}} 15 | {{ end -}} 16 |
17 |
18 | {{ end -}} 19 |
20 |
21 |
22 |
23 | {{ end }} -------------------------------------------------------------------------------- /src/Event/PullEvent.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | private IpPool $ipPool; 20 | 21 | public function __construct() 22 | { 23 | $this->ipPool = new IpPool(); 24 | } 25 | 26 | /** 27 | * @return Ip[] 28 | */ 29 | public function getIps(): array 30 | { 31 | return $this->ipPool->getIps(); 32 | } 33 | 34 | /** 35 | * @param Ip $ip 36 | */ 37 | public function addIp(Ip $ip): void 38 | { 39 | $this->ipPool->addIp($ip); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Job/YJob.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class YJob implements JobInterface 17 | { 18 | /** 19 | * @param Closure(mixed): mixed|JobInterface $job 20 | */ 21 | public function __construct(private Closure|JobInterface $job) {} 22 | 23 | public function __invoke($data): mixed 24 | { 25 | $U = static fn (Closure $f) => $f($f); 26 | $Y = static fn (Closure|JobInterface $f) => $U(static fn (Closure $x) => $f(static fn ($y) => $U($x)($y))); 27 | $job = $this->job; 28 | 29 | return $Y($job)($data); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /docs/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "commonjs": true, 6 | "es6": true, 7 | "node": true 8 | }, 9 | "extends": "eslint:recommended", 10 | "globals": { 11 | "Atomics": "readonly", 12 | "SharedArrayBuffer": "readonly" 13 | }, 14 | "parserOptions": { 15 | "parser": "babel-eslint", 16 | "ecmaVersion": 2020, 17 | "sourceType": "module" 18 | }, 19 | "rules": { 20 | "no-console": 0, 21 | "quotes": ["error", "single"], 22 | "comma-dangle": [ 23 | "error", 24 | { 25 | "arrays": "always-multiline", 26 | "objects": "always-multiline", 27 | "imports": "always-multiline", 28 | "exports": "always-multiline", 29 | "functions": "ignore" 30 | } 31 | ] 32 | } 33 | } -------------------------------------------------------------------------------- /docs/src/layouts/docs/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 |
5 |

{{ .Title }}

6 |
{{ .Content }}
7 |
8 | {{ $currentSection := .CurrentSection }} 9 | {{ range where .Site.RegularPages.ByWeight "Section" .Section }} 10 | {{ if in (.RelPermalink | string) $currentSection.RelPermalink }} 11 |
12 | 15 |
16 | {{ end }} 17 | {{ end }} 18 |
19 |
20 |
21 |
22 | {{ end }} -------------------------------------------------------------------------------- /tools/dev/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.6.0 2 | 3 | #FROM php:8.3-fpm-alpine as php 4 | FROM php:8.3-zts-alpine as php 5 | 6 | RUN apk add --update make curl 7 | 8 | COPY --from=composer:2.6.2 /usr/bin/composer /usr/bin/composer 9 | COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ 10 | RUN curl "https://github.com/jolicode/castor/releases/latest/download/castor.linux-amd64.phar" -Lso /usr/local/bin/castor && chmod u+x /usr/local/bin/castor 11 | 12 | RUN set -eux; \ 13 | install-php-extensions \ 14 | apcu \ 15 | ast \ 16 | intl \ 17 | opcache \ 18 | openswoole \ 19 | pcntl \ 20 | pcov \ 21 | zip \ 22 | parallel \ 23 | ; 24 | 25 | WORKDIR /flow 26 | 27 | #CMD ["php-fpm"] 28 | CMD ["tail", "-f", "/dev/null"] 29 | -------------------------------------------------------------------------------- /tools/phpstan/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "php": ">=8.3", 4 | "symfony/event-dispatcher": "^7.0", 5 | "symfony/messenger": "^7.0" 6 | }, 7 | "require-dev": { 8 | "amphp/amp": "^3.0", 9 | "openswoole/ide-helper": "^22.1.5", 10 | "phpstan/phpstan": "^1.12", 11 | "phpunit/phpunit": "^11.4", 12 | "react/async": "^4.3", 13 | "spatie/async": "^1.6", 14 | "symfony/doctrine-messenger": "^7.0", 15 | "symfony/orm-pack": "^2.4" 16 | }, 17 | "autoload": { 18 | "psr-4": { 19 | "Flow\\": "../../src" 20 | } 21 | }, 22 | "autoload-dev": { 23 | "psr-4": { 24 | "Flow\\Examples\\": "../../examples", 25 | "Flow\\Test\\": "../../tests" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /VERSIONING.md: -------------------------------------------------------------------------------- 1 | # Versioning and branching models 2 | 3 | This file explains the versioning and branching models of this project. 4 | 5 | ## Versioning 6 | 7 | The versioning is inspired by [Semantic Versioning](http://semver.org/) 8 | 9 | Given a version number MAJOR.MINOR.PATCH, increment the 10 | 11 | - MAJOR version when you make incompatible API changes 12 | - MINOR version when you add functionality in a backwards-compatible manner 13 | - PATCH version when you make backwards-compatible bug fixes 14 | 15 | ## Branching Model 16 | 17 | The branching is inspired by [@jbenet](https://github.com/jbenet) [simple git branching model](https://gist.github.com/jbenet/ee6c9ac48068889b0912) 18 | 19 | - `main` must always be deployable. 20 | - **all changes** are made through feature branches (pull-request + merge) 21 | - rebase to avoid/resolve conflicts; merge in to `main` 22 | -------------------------------------------------------------------------------- /src/Flow/FlowDecorator.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | abstract class FlowDecorator implements FlowInterface 19 | { 20 | /** 21 | * @param FlowInterface $flow 22 | */ 23 | public function __construct(private FlowInterface $flow) {} 24 | 25 | public function __invoke(Ip $ip): void 26 | { 27 | ($this->flow)($ip); 28 | } 29 | 30 | public function fn(array|Closure|FlowInterface|JobInterface $flow): FlowInterface 31 | { 32 | return $this->flow->fn($flow); 33 | } 34 | 35 | public function await(): void 36 | { 37 | $this->flow->await(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tools/phpunit/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | ../../tests 17 | 18 | 19 | 20 | 21 | 22 | ../../src 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Event/PoolEvent.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | private IpPool $ipPool; 20 | 21 | public function __construct() 22 | { 23 | $this->ipPool = new IpPool(); 24 | } 25 | 26 | /** 27 | * @param array> $ips 28 | */ 29 | public function addIps(array $ips): void 30 | { 31 | foreach ($ips as $ip) { 32 | $this->ipPool->addIp($ip); 33 | } 34 | } 35 | 36 | /** 37 | * @return array> 38 | */ 39 | public function getIps(): array 40 | { 41 | return $this->ipPool->getIps(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tools/infection/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | ../../tests 17 | 18 | 19 | 20 | 21 | 22 | ../../src 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/src/layouts/partials/head/stylesheet.html: -------------------------------------------------------------------------------- 1 | {{/* if eq (hugo.Environment) "development" -*/}} 2 | {{ $options := (dict "targetPath" "main.css" "enableSourceMap" true "includePaths" (slice "node_modules")) -}} 3 | {{ $css := resources.Get "scss/app.scss" | toCSS $options -}} 4 | 5 | {{/* else -}} 6 | {{ $options := (dict "targetPath" "main.css" "outputStyle" "compressed" "includePaths" (slice "node_modules")) -}} 7 | {{ $css := resources.Get "scss/app.scss" | toCSS $options | postCSS (dict "config" "config/postcss.config.js") -}} 8 | {{ $secureCSS := $css | resources.Fingerprint "sha512" -}} 9 | 10 | {{ end -*/}} 11 | -------------------------------------------------------------------------------- /.github/workflows/docs-deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Docs Deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - 1.x 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-22.04 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: actions/setup-node@v3 14 | with: 15 | node-version: '18' 16 | cache: 'npm' 17 | cache-dependency-path: 'docs/package-lock.json' 18 | 19 | - name: Install dependencies 20 | run: cd docs && npm install 21 | 22 | # - name: Check for linting errors 23 | # run: cd docs && npm test 24 | 25 | - name: Build production website 26 | run: cd docs && npm run build 27 | 28 | - name: Deploy to GitHub Pages 29 | uses: peaceiris/actions-gh-pages@v3 30 | with: 31 | github_token: ${{ secrets.GITHUB_TOKEN }} 32 | publish_dir: ./docs/src/public 33 | -------------------------------------------------------------------------------- /docs/src/assets/scss/components/_images.scss: -------------------------------------------------------------------------------- 1 | figure { 2 | margin: 2rem 0; 3 | } 4 | 5 | .figure-caption { 6 | margin: 0.25rem 0 0.75rem; 7 | } 8 | 9 | figure.wide { 10 | margin: 2rem -1.5rem; 11 | } 12 | 13 | figure.wide .figure-caption { 14 | margin: 0.25rem 1.5rem 0.75rem; 15 | } 16 | 17 | @include media-breakpoint-up(md) { 18 | figure.wide { 19 | margin: 2rem -2.5rem; 20 | } 21 | 22 | figure.wide .figure-caption { 23 | margin: 0.25rem 2.5rem 0.75rem; 24 | } 25 | } 26 | 27 | @include media-breakpoint-up(lg) { 28 | figure.wide { 29 | margin: 2rem -5rem; 30 | } 31 | 32 | figure.wide .figure-caption { 33 | margin: 0.25rem 5rem 0.75rem; 34 | } 35 | } 36 | 37 | .blur-up { 38 | filter: blur(5px); 39 | } 40 | 41 | .blur-up.lazyloaded { 42 | filter: unset; 43 | } 44 | 45 | .img-simple { 46 | margin-top: 0.375rem; 47 | margin-bottom: 1.25rem; 48 | } 49 | -------------------------------------------------------------------------------- /docs/src/layouts/blog/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 |
5 |

{{ .Title }}

6 |
{{ .Content }}
7 |
8 | {{ $paginator := .Paginate (.Data.Pages) -}} 9 | {{ range $paginator.Pages.ByWeight -}} 10 |
11 |
12 |

{{ .Params.title }}

13 |

{{ .Params.lead | safeHTML }}

14 | {{ partial "main/blog-meta.html" . -}} 15 |
16 |
17 | {{ end -}} 18 | {{ $.Scratch.Set "paginator" true }} 19 | {{ template "_internal/pagination.html" . }} 20 |
21 |
22 |
23 |
24 | {{ end }} -------------------------------------------------------------------------------- /docs/src/assets/scss/layouts/_pages.scss: -------------------------------------------------------------------------------- 1 | .docs-content > h2[id]::before, 2 | .docs-content > h3[id]::before, 3 | .docs-content > h4[id]::before { 4 | display: block; 5 | height: 6rem; 6 | margin-top: -6rem; 7 | content: ""; 8 | } 9 | 10 | .anchor { 11 | visibility: hidden; 12 | padding-left: 0.5rem; 13 | } 14 | 15 | h1:hover a, 16 | h2:hover a, 17 | h3:hover a, 18 | h4:hover a { 19 | visibility: visible; 20 | text-decoration: none; 21 | } 22 | 23 | .card-list { 24 | margin-top: 2.25rem; 25 | } 26 | 27 | .edit-page { 28 | margin-top: 3rem; 29 | font-size: $font-size-base; 30 | } 31 | 32 | .edit-page svg { 33 | margin-right: 0.5rem; 34 | margin-bottom: 0.25rem; 35 | } 36 | 37 | p.meta { 38 | margin-top: 0.5rem; 39 | font-size: $font-size-base; 40 | } 41 | 42 | .breadcrumb { 43 | margin-top: 2.25rem; 44 | font-size: $font-size-base; 45 | } 46 | 47 | .page-link:hover { 48 | text-decoration: none; 49 | } 50 | -------------------------------------------------------------------------------- /docs/src/assets/js/clipboard.js: -------------------------------------------------------------------------------- 1 | import Clipboard from 'clipboard'; 2 | 3 | var pre = document.getElementsByTagName('pre'); 4 | 5 | for (var i = 0; i < pre.length; ++ i) 6 | { 7 | var element = pre[i]; 8 | var mermaid = element.getElementsByClassName('language-mermaid')[0]; 9 | 10 | if (mermaid == null) { 11 | element.insertAdjacentHTML('afterbegin', ''); 12 | } 13 | } 14 | 15 | var clipboard = new Clipboard('.btn-copy', { 16 | 17 | target: function(trigger) { 18 | return trigger.nextElementSibling; 19 | }, 20 | 21 | }); 22 | 23 | clipboard.on('success', function(e) { 24 | 25 | /* 26 | console.info('Action:', e.action); 27 | console.info('Text:', e.text); 28 | console.info('Trigger:', e.trigger); 29 | */ 30 | 31 | e.clearSelection(); 32 | }); 33 | 34 | clipboard.on('error', function(e) { 35 | console.error('Action:', e.action); 36 | console.error('Trigger:', e.trigger); 37 | }); 38 | -------------------------------------------------------------------------------- /tools/psalm/psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tools/phan/phan.php: -------------------------------------------------------------------------------- 1 | '8.3', 7 | 'directory_list' => [ 8 | '../src/', 9 | '../tests/', 10 | '../vendor/', 11 | ], 12 | 'exclude_analysis_directory_list' => [ 13 | '../vendor/', 14 | ], 15 | 'plugins' => [ 16 | 'AlwaysReturnPlugin', 17 | 'DuplicateArrayKeyPlugin', 18 | 'PregRegexCheckerPlugin', 19 | 'PrintfCheckerPlugin', 20 | 'UnreachableCodePlugin', 21 | 'InvokePHPNativeSyntaxCheckPlugin', 22 | 'PHPUnitAssertionPlugin', 23 | 'EmptyStatementListPlugin', 24 | 'LoopVariableReusePlugin', 25 | 'RedundantAssignmentPlugin', 26 | 'PHPUnitNotDeadCodePlugin', 27 | 'WhitespacePlugin', 28 | 'PHPDocRedundantPlugin', 29 | ], 30 | 'plugin_config' => [ 31 | 'php_native_syntax_check_max_processes' => 4, 32 | ], 33 | 'suppress_issue_types' => [ 34 | ], 35 | ]; 36 | -------------------------------------------------------------------------------- /docs/src/assets/js/highlight.js: -------------------------------------------------------------------------------- 1 | import hljs from 'highlight.js/lib/core'; 2 | 3 | import javascript from 'highlight.js/lib/languages/javascript'; 4 | import json from 'highlight.js/lib/languages/json'; 5 | import bash from 'highlight.js/lib/languages/bash'; 6 | import xml from 'highlight.js/lib/languages/xml'; 7 | import ini from 'highlight.js/lib/languages/ini'; 8 | import yaml from 'highlight.js/lib/languages/yaml'; 9 | import markdown from 'highlight.js/lib/languages/markdown'; 10 | 11 | hljs.registerLanguage('javascript', javascript); 12 | hljs.registerLanguage('json', json); 13 | hljs.registerLanguage('bash', bash); 14 | hljs.registerLanguage('html', xml); 15 | hljs.registerLanguage('ini', ini); 16 | hljs.registerLanguage('toml', ini); 17 | hljs.registerLanguage('yaml', yaml); 18 | hljs.registerLanguage('md', markdown); 19 | 20 | document.addEventListener('DOMContentLoaded', () => { 21 | document.querySelectorAll('pre code:not(.language-mermaid)').forEach((block) => { 22 | hljs.highlightElement(block); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /docs/src/content/en/docs/getting-started/ip-strategy.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Ip Strategy" 3 | description: "Ip Strategy." 4 | lead: "Ip Strategy." 5 | date: 2020-10-13T15:21:01+02:00 6 | lastmod: 2020-10-13T15:21:01+02:00 7 | draft: false 8 | images: [] 9 | menu: 10 | docs: 11 | parent: "getting-started" 12 | weight: 40 13 | toc: true 14 | --- 15 | 16 | # Ip Strategy 17 | 18 | When processing Flow with one or multiple Ips, you can choose a strategy that will sequence the order of processing Ip. 19 | 20 | ## LinearIpStrategy 21 | 22 | This process Ip by order : first in, first out. 23 | 24 | ## StackIpStrategy 25 | 26 | This process Ip as a stack order : push ip to the top of the stack, then order ip retrieval from the top stack to bottom. 27 | 28 | ## MaxIpStrategy 29 | 30 | This process Ip as soon less Ip are currently process than the current max. 31 | You can embed it by a custom strategy with is `LinearIpStrategy` by default. 32 | 33 | ## Make your Ip Strategy 34 | 35 | You can make your custom Ip strategy by implementing `Flow\IpStrategyInterface` 36 | -------------------------------------------------------------------------------- /docs/src/layouts/sitemap.xml: -------------------------------------------------------------------------------- 1 | {{ printf "" | safeHTML }} 2 | 4 | {{ range .Data.Pages }}{{ if ne .Params.sitemap_exclude true }} 5 | 6 | {{ .Permalink }}{{ if not .Lastmod.IsZero }} 7 | {{ safeHTML ( .Lastmod.Format "2006-01-02T15:04:05-07:00" ) }}{{ end }}{{ with .Sitemap.ChangeFreq }} 8 | {{ . }}{{ end }}{{ if ge .Sitemap.Priority 0.0 }} 9 | {{ .Sitemap.Priority }}{{ end }}{{ if .IsTranslated }}{{ range .Translations }} 10 | {{ end }} 15 | {{ end }} 20 | 21 | {{ end }}{{ end }} 22 | 23 | -------------------------------------------------------------------------------- /docs/src/assets/scss/app.scss: -------------------------------------------------------------------------------- 1 | /** Import Bootstrap functions */ 2 | @import "../../../node_modules/bootstrap/scss/functions"; 3 | 4 | /** Import theme variables */ 5 | @import "common/variables"; 6 | 7 | /** Import Bootstrap */ 8 | @import "../../../node_modules/bootstrap/scss/bootstrap"; 9 | 10 | /** Import highlight.js */ 11 | // @import "highlight.js/scss/github-dark-dimmed"; 12 | 13 | /** Import KaTeX */ 14 | @import "../../../node_modules/katex/dist/katex"; 15 | 16 | /** Import theme styles */ 17 | @import "common/fonts"; 18 | @import "common/global"; 19 | @import "common/dark"; 20 | @import "common/sepia"; 21 | @import "components/alerts"; 22 | @import "components/buttons"; 23 | @import "components/code"; 24 | @import "components/syntax"; 25 | @import "components/comments"; 26 | @import "components/forms"; 27 | @import "components/images"; 28 | @import "components/mermaid"; 29 | @import "components/search"; 30 | @import "components/tables"; 31 | @import "layouts/footer"; 32 | @import "layouts/header"; 33 | @import "layouts/pages"; 34 | @import "layouts/posts"; 35 | @import "layouts/sidebar"; 36 | -------------------------------------------------------------------------------- /tests/AsyncHandler/AsyncHandlerTest.php: -------------------------------------------------------------------------------- 1 | $x, 22 | static fn ($x) => $x, 23 | static function ($data) use (&$result) { 24 | [$n1, $n2] = $data; 25 | $result = $n1 + $n2; 26 | 27 | return static function ($callback) use ($result) { 28 | $callback($result); 29 | }; 30 | }, 31 | new Ip([2, 6]), 32 | static function () {} 33 | ); 34 | 35 | $asyncHandler = new AsyncHandler(); 36 | $asyncHandler->async($event); 37 | assertSame(8, $result); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /docs/src/config/postcss.config.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer'); 2 | const purgecss = require('@fullhuman/postcss-purgecss'); 3 | const whitelister = require('purgecss-whitelister'); 4 | 5 | module.exports = { 6 | plugins: [ 7 | autoprefixer(), 8 | purgecss({ 9 | content: [ 10 | './layouts/**/*.html', 11 | './content/**/*.md', 12 | ], 13 | safelist: [ 14 | 'lazyloaded', 15 | 'table', 16 | 'thead', 17 | 'tbody', 18 | 'tr', 19 | 'th', 20 | 'td', 21 | 'h5', 22 | 'alert-link', 23 | ...whitelister([ 24 | './assets/scss/components/_buttons.scss', 25 | './assets/scss/components/_code.scss', 26 | './assets/scss/components/_diagrams.scss', 27 | './assets/scss/components/_syntax.scss', 28 | './assets/scss/components/_search.scss', 29 | './assets/scss/common/_dark.scss', 30 | './../node_modules/bootstrap/scss/_dropdown.scss', 31 | './../node_modules/katex/dist/katex.css', 32 | ]), 33 | ], 34 | }), 35 | ], 36 | } 37 | -------------------------------------------------------------------------------- /docs/src/layouts/partials/head/twitter_cards.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ with $.Params.images -}} 7 | 8 | {{ else -}} 9 | {{ $images := $.Resources.ByType "image" -}} 10 | {{ $featured := $images.GetMatch "*feature*" -}} 11 | {{ if not $featured -}} 12 | {{ $featured = $images.GetMatch "{*cover*,*thumbnail*}" -}} 13 | {{ end -}} 14 | {{ with $featured -}} 15 | 16 | {{ else -}} 17 | {{ with $.Site.Params.images -}} 18 | 19 | {{ else -}} 20 | 21 | {{ end -}} 22 | {{ end -}} 23 | {{ end -}} 24 | -------------------------------------------------------------------------------- /tests/AsyncHandler/DeferAsyncHandlerTest.php: -------------------------------------------------------------------------------- 1 | $x, 22 | static fn ($x) => $x, 23 | static function (array $args) use (&$result) { 24 | [[$n1, $n2], $defer] = $args; 25 | $result = $n1 + $n2; 26 | 27 | return static function ($callback) use ($result) { 28 | $callback($result); 29 | }; 30 | }, 31 | new Ip([1, 7]), 32 | static function () {} 33 | ); 34 | 35 | $asyncHandler = new DeferAsyncHandler(); 36 | $asyncHandler->async($event); 37 | assertSame(8, $result); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2023 Darkwood 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ##Dev 3 | ##------------ 4 | 5 | dev: ## Start dev server 6 | composer dev 7 | 8 | docs-serve: ## Start documentation server locally 9 | composer docs-serve 10 | 11 | editorconfig-fixer: ## Fixes text files based on given .editorconfig declarations 12 | composer editorconfig-fixer 13 | 14 | infection: ## Run Infection 15 | composer infection 16 | 17 | php-cs-fixer: ## Check and fix coding styles using PHP CS Fixer 18 | composer php-cs-fixer 19 | 20 | phan: ## Run Phan 21 | composer phan 22 | 23 | phpcbf: ## Clean code with PHP Code Beautifier and Fixer 24 | composer phpcbf 25 | 26 | phpcs: ## Run PHP Code Sniffer 27 | composer phpcs 28 | 29 | phpmd: ## Run PHP Mess Detector 30 | composer phpmd 31 | 32 | phpstan: ## Execute PHPStan analysis 33 | composer phpstan 34 | 35 | phpunit: ## Launch PHPUnit test suite 36 | composer phpunit 37 | 38 | psalm: ## Run Psalm 39 | composer psalm 40 | 41 | # DEFAULT 42 | .DEFAULT_GOAL := help 43 | help: 44 | @grep -E '(^[a-zA-Z_-]+:.*?##.*$$)|(^##)' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' | sed -e 's/\[32m##/[33m/' 45 | .PHONY: help 46 | 47 | ## 48 | -------------------------------------------------------------------------------- /tests/IpStrategy/StackIpStrategyTest.php: -------------------------------------------------------------------------------- 1 | push(new PushEvent($ip1)); 22 | $strategy->push(new PushEvent($ip2)); 23 | 24 | $pullEvent = new PullEvent(); 25 | $strategy->pull($pullEvent); 26 | self::assertNotEmpty($pullEvent->getIps()); 27 | self::assertSame($ip2, $pullEvent->getIps()[0]); 28 | 29 | $pullEvent = new PullEvent(); 30 | $strategy->pull($pullEvent); 31 | self::assertNotEmpty($pullEvent->getIps()); 32 | self::assertSame($ip1, $pullEvent->getIps()[0]); 33 | 34 | $pullEvent = new PullEvent(); 35 | $strategy->pull($pullEvent); 36 | self::assertEmpty($pullEvent->getIps()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/IpStrategy/LinearIpStrategyTest.php: -------------------------------------------------------------------------------- 1 | push(new PushEvent($ip1)); 22 | $strategy->push(new PushEvent($ip2)); 23 | 24 | $pullEvent = new PullEvent(); 25 | $strategy->pull($pullEvent); 26 | self::assertNotEmpty($pullEvent->getIps()); 27 | self::assertSame($ip1, $pullEvent->getIps()[0]); 28 | 29 | $pullEvent = new PullEvent(); 30 | $strategy->pull($pullEvent); 31 | self::assertNotEmpty($pullEvent->getIps()); 32 | self::assertSame($ip2, $pullEvent->getIps()[0]); 33 | 34 | $pullEvent = new PullEvent(); 35 | $strategy->pull($pullEvent); 36 | self::assertEmpty($pullEvent->getIps()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/IpPool.php: -------------------------------------------------------------------------------- 1 | > 14 | */ 15 | private array $ips = []; 16 | 17 | /** 18 | * @param Ip $ip 19 | * 20 | * @return callable A function that removes the added IP from the pool when called 21 | */ 22 | public function addIp(Ip $ip): callable 23 | { 24 | $this->ips[] = $ip; 25 | 26 | return function () use ($ip) { 27 | $this->ips = array_filter($this->ips, static function ($iteratorIp) use ($ip) { 28 | return $iteratorIp !== $ip; 29 | }); 30 | }; 31 | } 32 | 33 | /** 34 | * @return array> 35 | */ 36 | public function getIps(): array 37 | { 38 | return $this->ips; 39 | } 40 | 41 | /** 42 | * @return null|Ip 43 | */ 44 | public function shiftIp(): ?Ip 45 | { 46 | return array_shift($this->ips); 47 | } 48 | 49 | /** 50 | * @return null|Ip 51 | */ 52 | public function popIp(): ?Ip 53 | { 54 | return array_pop($this->ips); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /docs/src/assets/scss/components/_code.scss: -------------------------------------------------------------------------------- 1 | pre, 2 | code, 3 | kbd, 4 | samp { 5 | font-family: $font-family-monospace; 6 | font-size: $font-size-sm; 7 | border-radius: $border-radius; 8 | } 9 | 10 | code { 11 | background: $beige; 12 | color: $black; 13 | padding: 0.25rem 0.5rem; 14 | } 15 | 16 | pre { 17 | margin: 2rem 0; 18 | } 19 | 20 | pre code { 21 | display: block; 22 | overflow-x: auto; 23 | line-height: $line-height-base; 24 | padding: 1.25rem 1.5rem; 25 | tab-size: 4; 26 | scrollbar-width: thin; 27 | scrollbar-color: transparent transparent; 28 | } 29 | 30 | .hljs { 31 | padding: 1.5rem !important; 32 | } 33 | 34 | @include media-breakpoint-down(sm) { 35 | pre, 36 | code, 37 | kbd, 38 | samp { 39 | border-radius: 0; 40 | } 41 | 42 | pre { 43 | margin: 2rem -1.5rem; 44 | } 45 | } 46 | 47 | pre code::-webkit-scrollbar { 48 | height: 5px; 49 | } 50 | 51 | pre code::-webkit-scrollbar-thumb { 52 | background: $gray-400; 53 | } 54 | 55 | pre code:hover { 56 | scrollbar-width: thin; 57 | scrollbar-color: $gray-500 transparent; 58 | } 59 | 60 | pre code::-webkit-scrollbar-thumb:hover { 61 | background: $gray-500; 62 | } 63 | 64 | code.language-mermaid { 65 | background: none; 66 | } 67 | -------------------------------------------------------------------------------- /docs/src/content/en/docs/getting-started/async-handler.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Async Handler" 3 | description: "Async Handler." 4 | lead: "Async Handler." 5 | date: 2020-10-13T15:21:01+02:00 6 | lastmod: 2020-10-13T15:21:01+02:00 7 | draft: false 8 | images: [] 9 | menu: 10 | docs: 11 | parent: "getting-started" 12 | weight: 35 13 | toc: true 14 | --- 15 | 16 | # Async Handler 17 | 18 | When processing Flow at async step, you can choose a handler that will process asynchronously the Ip. 19 | 20 | ## AsyncHandler 21 | 22 | This is the default one. Ip is async processed immediately. 23 | 24 | ## BatchAsyncHandler 25 | 26 | This async process Ip as batch capability : the handler will wait for a certain amount of async messages ($batchSize) to be processed before pushing them. 27 | 28 | ## DeferAsyncHandler 29 | 30 | This async process Ip to offer defer capability : the handler will pass [$data, $defer] as entry for the job. In that case, the job can fine control the async process. $defer is a callable that embark two callbacks 31 | - an complete callback to store result 32 | - an async callback to go to the next async call. 33 | 34 | ## Make your Async Handler 35 | 36 | You can make your custom Ip strategy by implementing `Flow\AsyncHandlerInterface` 37 | -------------------------------------------------------------------------------- /docs/src/layouts/_default/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ partial "head/head.html" . }} 4 | {{ if eq .Kind "home" -}} 5 | {{ .Scratch.Set "class" "home vh-100 d-flex flex-column" -}} 6 | {{ .Scratch.Set "class-container" "flex-grow-1 d-flex" -}} 7 | {{ else if eq .Kind "404" -}} 8 | {{ .Scratch.Set "class" "error404" -}} 9 | {{ .Scratch.Set "class-container" "" -}} 10 | {{ else if eq .Kind "page" -}} 11 | {{ .Scratch.Set "class" .Type -}} 12 | {{ .Scratch.Add "class" " single" -}} 13 | {{ .Scratch.Set "class-container" "" -}} 14 | {{ else -}} 15 | {{ .Scratch.Set "class" .Type -}} 16 | {{ .Scratch.Add "class" " list" -}} 17 | {{ .Scratch.Set "class-container" "" -}} 18 | {{ end -}} 19 | 20 | {{ partial "header/header.html" . }} 21 |
22 |
23 | {{ block "main" . }}{{ end }} 24 |
25 |
26 | {{ block "sidebar-prefooter" . }}{{ end }} 27 | {{ block "sidebar-footer" . }}{{ end }} 28 | {{ partial "footer/footer.html" . }} 29 | {{ partial "footer/script-footer.html" . }} 30 | 31 | -------------------------------------------------------------------------------- /docs/src/content/en/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title : "Flow" 3 | description: "Assemble your code by adopting asynchronous as native implementation and build with functional programming and monads." 4 | lead: "Assemble your code by adopting asynchronous as native implementation and build with functional programming and monads." 5 | date: 2020-10-06T08:47:36+00:00 6 | lastmod: 2020-10-06T08:47:36+00:00 7 | draft: false 8 | images: [] 9 | --- 10 | 11 | ## Usage 12 | 13 | ```php 14 | create(static function() { 37 | yield fn (D1 $data1) => new D2($data1->n1 += 1); 38 | yield fn (D2 $data2) => new D3($data2->n2 * 2); 39 | yield function(D3 $data3) { 40 | printf("my number %d\n", $ip->data->n3)); // display 'my number 10' 41 | 42 | return new D4($data3->n3); 43 | }; 44 | }); 45 | 46 | $ip = new Ip(new D1(4)); 47 | $flow($ip); 48 | $flow->await(); 49 | ``` 50 | -------------------------------------------------------------------------------- /examples/Transport/Receiver/CollectionReceiver.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | private SplObjectStorage $envelopePool; 17 | 18 | /** 19 | * @param iterable $receivers 20 | */ 21 | public function __construct(private iterable $receivers) 22 | { 23 | $this->envelopePool = new SplObjectStorage(); 24 | } 25 | 26 | public function get(): iterable 27 | { 28 | foreach ($this->receivers as $receiver) { 29 | foreach ($receiver->get() as $envelope) { 30 | $this->envelopePool[$envelope] = $receiver; 31 | yield $envelope; 32 | } 33 | } 34 | } 35 | 36 | public function ack(Envelope $envelope): void 37 | { 38 | $this->envelopePool[$envelope]->ack($envelope); 39 | } 40 | 41 | public function reject(Envelope $envelope): void 42 | { 43 | $this->envelopePool[$envelope]->reject($envelope); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /docs/src/content/en/docs/getting-started/introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Introduction" 3 | description: "Introduction." 4 | lead: "Introduction." 5 | date: 2020-10-13T15:21:01+02:00 6 | lastmod: 2020-10-13T15:21:01+02:00 7 | draft: false 8 | images: [] 9 | menu: 10 | docs: 11 | parent: "getting-started" 12 | weight: 10 13 | toc: true 14 | --- 15 | 16 | # Flow 17 | 18 | ## Why ? 19 | 20 | Flow concept aims to solve 21 | 22 | - Adopt asynchronous as native implementation 23 | - Build your code with functional programming and monoids 24 | - Assemble your code visually 25 | 26 | ## Installation 27 | 28 | PHP 8.3 is the minimal version to use _Flow_ 29 | The recommended way to install it through [Composer](http://getcomposer.org/) and execute 30 | 31 | ```bash 32 | composer require darkwood/flow 33 | ``` 34 | 35 | ## Usage 36 | 37 | A working script is available in the bundled `examples` directory 38 | 39 | - Run Flow : `php examples/flow.php` 40 | - Start Server : `php examples/server.php` 41 | - Start Client(s) : `php examples/client.php` 42 | 43 | Messaging part require to install [Docker](https://www.docker.com) and execute `docker-compose up -d` 44 | 45 | ## Documentation 46 | 47 | [https://darkwood-com.github.io/flow](https://darkwood-com.github.io/flow) 48 | 49 | ## License 50 | 51 | _Flow_ is released under the MIT License. 52 | -------------------------------------------------------------------------------- /src/Event/AsyncEvent.php: -------------------------------------------------------------------------------- 1 | $job 19 | * @param Ip $ip 20 | */ 21 | public function __construct( 22 | private Closure $async, 23 | private Closure $defer, 24 | private Closure|JobInterface $job, 25 | private Ip $ip, 26 | private Closure $callback 27 | ) {} 28 | 29 | public function getAsync(): Closure 30 | { 31 | return $this->async; 32 | } 33 | 34 | public function getDefer(): Closure 35 | { 36 | return $this->defer; 37 | } 38 | 39 | /** 40 | * @return Closure|JobInterface 41 | */ 42 | public function getJob(): Closure|JobInterface 43 | { 44 | return $this->job; 45 | } 46 | 47 | /** 48 | * @return Ip 49 | */ 50 | public function getIp(): Ip 51 | { 52 | return $this->ip; 53 | } 54 | 55 | public function getCallback(): Closure 56 | { 57 | return $this->callback; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /docs/src/assets/scss/components/_syntax.scss: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Based on Ascetic by (c) Ivan Sagalaev 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 1.25rem 1.5rem; 11 | background: $beige; 12 | color: $body-color; 13 | } 14 | 15 | .hljs-string, 16 | .hljs-variable, 17 | .hljs-template-variable, 18 | .hljs-symbol, 19 | .hljs-bullet, 20 | .hljs-section, 21 | .hljs-addition, 22 | .hljs-attribute, 23 | .hljs-link { 24 | color: $pink-500; 25 | } 26 | 27 | .hljs-comment, 28 | .hljs-quote, 29 | .hljs-meta, 30 | .hljs-deletion { 31 | color: #888; 32 | } 33 | 34 | .hljs-keyword, 35 | .hljs-selector-tag, 36 | .hljs-section, 37 | .hljs-name, 38 | .hljs-type, 39 | .hljs-strong { 40 | font-weight: bold; 41 | } 42 | 43 | .hljs-emphasis { 44 | font-style: italic; 45 | } 46 | 47 | [data-dark-mode] body .hljs { 48 | background: $body-overlay-dark; 49 | color: $body-color-dark; 50 | } 51 | 52 | [data-dark-mode] body .hljs-string, 53 | [data-dark-mode] body .hljs-variable, 54 | [data-dark-mode] body .hljs-template-variable, 55 | [data-dark-mode] body .hljs-symbol, 56 | [data-dark-mode] body .hljs-bullet, 57 | [data-dark-mode] body .hljs-section, 58 | [data-dark-mode] body .hljs-addition, 59 | [data-dark-mode] body .hljs-attribute, 60 | [data-dark-mode] body .hljs-link { 61 | color: $blue-300; 62 | } 63 | -------------------------------------------------------------------------------- /tests/Examples/Transport/Sender/CollectionSenderTest.php: -------------------------------------------------------------------------------- 1 | 0]); 19 | $senders = array_map(function () use ($counter) { 20 | return new class($counter) implements SenderInterface { 21 | /** 22 | * @param ArrayObject $counter 23 | */ 24 | public function __construct(private ArrayObject $counter) {} 25 | 26 | public function send(Envelope $envelope): Envelope 27 | { 28 | $this->counter['send']++; 29 | 30 | return $envelope; 31 | } 32 | }; 33 | }, array_fill(0, 10, 0)); 34 | $collectionSender = new CollectionSender($senders); 35 | $collectionSender->send(new Envelope(new stdClass())); 36 | 37 | self::assertSame(10, $counter['send']); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/AsyncHandler/AsyncHandler.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | final class AsyncHandler implements AsyncHandlerInterface 19 | { 20 | /** 21 | * @var IpPool 22 | */ 23 | private IpPool $ipPool; 24 | 25 | public function __construct() 26 | { 27 | $this->ipPool = new IpPool(); 28 | } 29 | 30 | public static function getSubscribedEvents() 31 | { 32 | return [ 33 | Event::ASYNC => 'async', 34 | Event::POOL => 'pool', 35 | ]; 36 | } 37 | 38 | public function async(AsyncEvent $event): void 39 | { 40 | $ip = $event->getIp(); 41 | $async = $event->getAsync(); 42 | $asyncJob = $async($event->getJob()); 43 | 44 | $popIp = $this->ipPool->addIp($ip); 45 | $next = $asyncJob($ip->data); 46 | $next(static function ($data) use ($event, $popIp) { 47 | $event->getCallback()($data); 48 | $popIp(); 49 | }); 50 | } 51 | 52 | public function pool(PoolEvent $event): void 53 | { 54 | $event->addIps($this->ipPool->getIps()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /examples/Transport/CollectionTransport.php: -------------------------------------------------------------------------------- 1 | $transports 19 | */ 20 | public function __construct(iterable $transports) 21 | { 22 | $this->collectionReceiver = new CollectionReceiver($transports); 23 | $this->collectionSender = new CollectionSender($transports); 24 | } 25 | 26 | public function get(): iterable 27 | { 28 | return $this->collectionReceiver->get(); 29 | } 30 | 31 | public function ack(Envelope $envelope): void 32 | { 33 | $this->collectionReceiver->ack($envelope); 34 | } 35 | 36 | public function reject(Envelope $envelope): void 37 | { 38 | $this->collectionReceiver->reject($envelope); 39 | } 40 | 41 | public function send(Envelope $envelope): Envelope 42 | { 43 | return $this->collectionSender->send($envelope); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Flow/YFlow.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | class YFlow extends Flow 23 | { 24 | /** 25 | * @param null|Closure(ExceptionInterface): void|JobInterface $errorJob 26 | * @param null|IpStrategyInterface $ipStrategy 27 | * @param null|AsyncHandlerInterface $asyncHandler 28 | * @param null|DriverInterface $driver 29 | */ 30 | public function __construct( 31 | Closure|JobInterface $job, 32 | null|Closure|JobInterface $errorJob = null, 33 | ?IpStrategyInterface $ipStrategy = null, 34 | ?EventDispatcherInterface $dispatcher = null, 35 | ?AsyncHandlerInterface $asyncHandler = null, 36 | ?DriverInterface $driver = null 37 | ) { 38 | parent::__construct(new YJob($job), $errorJob, $ipStrategy, $dispatcher, $asyncHandler, $driver); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/client.php: -------------------------------------------------------------------------------- 1 | 'pdo_sqlite', 13 | 'path' => __DIR__ . '/flow.sqlite', 14 | ]); 15 | $transport = new DoctrineIpTransport($connection, uniqid('transport_', true)); 16 | 17 | $client = new Client($transport, $transport); 18 | 19 | $ip = long2ip(random_int(ip2long('10.0.0.0'), ip2long('10.255.255.255'))); 20 | for ($i = 0; $i < 3; $i++) { 21 | $data = new ArrayObject([ 22 | 'client' => $ip, 23 | 'id' => $i, 24 | 'number' => random_int(1, 9), 25 | ]); 26 | $delay = random_int(1, 10); // simulating 1 and 10 second delay 27 | 28 | printf("Client %s #%d: call for number %d with delay %d seconds\n", $data['client'], $data['id'], $data['number'], $delay); 29 | $client->call($data, $delay * 1000); 30 | } 31 | 32 | $client->wait([ 33 | ArrayObject::class => [static function (ArrayObject $data) { 34 | if (null === $data['number']) { 35 | printf("Client %s #%d: error in process\n", $data['client'], $data['id']); 36 | } else { 37 | printf("Client %s #%d: result number %d\n", $data['client'], $data['id'], $data['number']); 38 | } 39 | }], 40 | ]); 41 | -------------------------------------------------------------------------------- /src/Flow/LambdaFlow.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | class LambdaFlow extends Flow 23 | { 24 | /** 25 | * @param null|Closure(ExceptionInterface): void|JobInterface $errorJob 26 | * @param null|IpStrategyInterface $ipStrategy 27 | * @param null|AsyncHandlerInterface $asyncHandler 28 | * @param null|DriverInterface $driver 29 | */ 30 | public function __construct( 31 | string $expression, 32 | null|Closure|JobInterface $errorJob = null, 33 | ?IpStrategyInterface $ipStrategy = null, 34 | ?EventDispatcherInterface $dispatcher = null, 35 | ?AsyncHandlerInterface $asyncHandler = null, 36 | ?DriverInterface $driver = null 37 | ) { 38 | parent::__construct(new LambdaJob($expression), $errorJob, $ipStrategy, $dispatcher, $asyncHandler, $driver); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/AsyncHandler/DeferAsyncHandler.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | final class DeferAsyncHandler implements AsyncHandlerInterface 19 | { 20 | /** 21 | * @var IpPool 22 | */ 23 | private IpPool $ipPool; 24 | 25 | public function __construct() 26 | { 27 | $this->ipPool = new IpPool(); 28 | } 29 | 30 | public static function getSubscribedEvents() 31 | { 32 | return [ 33 | Event::ASYNC => 'async', 34 | Event::POOL => 'pool', 35 | ]; 36 | } 37 | 38 | public function async(AsyncEvent $event): void 39 | { 40 | $ip = $event->getIp(); 41 | $job = $event->getJob(); 42 | 43 | $popIp = $this->ipPool->addIp($ip); 44 | $next = $job([$ip->data, $event->getDefer()]); 45 | $next(static function ($result) use ($event, $popIp) { 46 | [$data] = $result; 47 | $callback = $event->getCallback(); 48 | $callback($data); 49 | $popIp(); 50 | }); 51 | } 52 | 53 | public function pool(PoolEvent $event): void 54 | { 55 | $event->addIps($this->ipPool->getIps()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/IpStrategy/StackIpStrategy.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class StackIpStrategy implements IpStrategyInterface 20 | { 21 | /** 22 | * @var IpPool 23 | */ 24 | private IpPool $ipPool; 25 | 26 | public function __construct() 27 | { 28 | $this->ipPool = new IpPool(); 29 | } 30 | 31 | public static function getSubscribedEvents() 32 | { 33 | return [ 34 | Event::PUSH => 'push', 35 | Event::PULL => 'pull', 36 | Event::POOL => 'pool', 37 | ]; 38 | } 39 | 40 | /** 41 | * @param PushEvent $event 42 | */ 43 | public function push(PushEvent $event): void 44 | { 45 | $this->ipPool->addIp($event->getIp()); 46 | } 47 | 48 | /** 49 | * @param PullEvent $event 50 | */ 51 | public function pull(PullEvent $event): void 52 | { 53 | $ip = $this->ipPool->popIp(); 54 | if ($ip !== null) { 55 | $event->addIp($ip); 56 | } 57 | } 58 | 59 | public function pool(PoolEvent $event): void 60 | { 61 | $event->addIps($this->ipPool->getIps()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/IpStrategy/LinearIpStrategy.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class LinearIpStrategy implements IpStrategyInterface 20 | { 21 | /** 22 | * @var IpPool 23 | */ 24 | private IpPool $ipPool; 25 | 26 | public function __construct() 27 | { 28 | $this->ipPool = new IpPool(); 29 | } 30 | 31 | public static function getSubscribedEvents(): array 32 | { 33 | return [ 34 | Event::PUSH => 'push', 35 | Event::PULL => 'pull', 36 | Event::POOL => 'pool', 37 | ]; 38 | } 39 | 40 | /** 41 | * @param PushEvent $event 42 | */ 43 | public function push(PushEvent $event): void 44 | { 45 | $this->ipPool->addIp($event->getIp()); 46 | } 47 | 48 | /** 49 | * @param PullEvent $event 50 | */ 51 | public function pull(PullEvent $event): void 52 | { 53 | $ip = $this->ipPool->shiftIp(); 54 | if ($ip !== null) { 55 | $event->addIp($ip); 56 | } 57 | } 58 | 59 | public function pool(PoolEvent $event): void 60 | { 61 | $event->addIps($this->ipPool->getIps()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /docs/src/content/en/docs/getting-started/license.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "License" 3 | description: "License." 4 | lead: "License." 5 | date: 2020-10-13T15:21:01+02:00 6 | lastmod: 2020-10-13T15:21:01+02:00 7 | draft: false 8 | images: [] 9 | menu: 10 | docs: 11 | parent: "getting-started" 12 | weight: 70 13 | toc: true 14 | --- 15 | 16 | The MIT License (MIT) 17 | 18 | Copyright (c) 2023 Darkwood 19 | 20 | Permission is hereby granted, free of charge, to any person obtaining a copy of 21 | this software and associated documentation files (the "Software"), to deal in 22 | the Software without restriction, including without limitation the rights to 23 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 24 | the Software, and to permit persons to whom the Software is furnished to do so, 25 | subject to the following conditions: 26 | 27 | The above copyright notice and this permission notice shall be included in all 28 | copies or substantial portions of the Software. 29 | 30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 32 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 33 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 34 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 35 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 36 | -------------------------------------------------------------------------------- /tools/phpunit/castor.php: -------------------------------------------------------------------------------- 1 | $xdebugMode ?? 'coverage']; 28 | } 29 | 30 | if ($testDox) { 31 | $command[] = '--testdox'; 32 | } 33 | 34 | if ($coverateHtmlPath !== null) { 35 | $command[] = '--coverage-html'; 36 | $command[] = $coverateHtmlPath; 37 | } 38 | 39 | if ($coverateHtmlXml !== null) { 40 | $command[] = '--coverage-clover'; 41 | $command[] = $coverateHtmlXml; 42 | } 43 | 44 | return run($command, $environment, allowFailure: true)->getExitCode(); 45 | } 46 | -------------------------------------------------------------------------------- /examples/Transport/Client.php: -------------------------------------------------------------------------------- 1 | sender->send($ip); 31 | } 32 | 33 | /** 34 | * @param callable[][]|HandlerDescriptor[][] $handlers 35 | */ 36 | public function wait(array $handlers): void 37 | { 38 | $bus = new MessageBus([ 39 | new HandleMessageMiddleware(new HandlersLocator($handlers)), 40 | ]); 41 | $worker = new Worker(['transport' => $this->receiver], $bus); 42 | $worker->run(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/src/assets/scss/components/_search.scss: -------------------------------------------------------------------------------- 1 | .navbar-form { 2 | position: relative; 3 | } 4 | 5 | #suggestions { 6 | position: absolute; 7 | left: 0; 8 | margin-top: 0.5rem; 9 | width: calc(100vw - 3rem); 10 | z-index: $zindex-dropdown; 11 | } 12 | 13 | #suggestions a { 14 | display: block; 15 | text-decoration: none; 16 | padding: 0.75rem; 17 | margin: 0 0.5rem; 18 | } 19 | 20 | #suggestions a:focus { 21 | background: $gray-100; 22 | outline: 0; 23 | } 24 | 25 | #suggestions div:not(:first-child) { 26 | border-top: 1px dashed $gray-200; 27 | } 28 | 29 | #suggestions div:first-child { 30 | margin-top: 0.5rem; 31 | } 32 | 33 | #suggestions div:last-child { 34 | margin-bottom: 0.5rem; 35 | } 36 | 37 | #suggestions a:hover { 38 | background: $gray-100; 39 | } 40 | 41 | #suggestions span { 42 | display: flex; 43 | font-size: $font-size-base; 44 | } 45 | 46 | #suggestions span:first-child { 47 | font-weight: $headings-font-weight; 48 | color: $black; 49 | } 50 | 51 | #suggestions span:nth-child(2) { 52 | color: $gray-700; 53 | } 54 | 55 | @include media-breakpoint-up(sm) { 56 | #suggestions { 57 | width: 31.125rem; 58 | } 59 | 60 | #suggestions a { 61 | display: flex; 62 | } 63 | 64 | #suggestions span:first-child { 65 | width: 9rem; 66 | padding-right: 1rem; 67 | border-right: 1px solid $gray-200; 68 | display: inline-block; 69 | text-align: right; 70 | } 71 | 72 | #suggestions span:nth-child(2) { 73 | width: 19rem; 74 | padding-left: 1rem; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /docs/src/layouts/shortcodes/img.html: -------------------------------------------------------------------------------- 1 | {{ $image := .Page.Resources.GetMatch (printf "*%s*" (.Get "src")) -}} 2 | {{ $lqip := $image.Resize $.Site.Params.lqipWidth -}} 3 | 4 | {{ $imgSrc := "" -}} 5 | {{ $imgSrcSet := slice -}} 6 | 7 | {{ $widths := $.Site.Params.landscapePhotoWidths -}} 8 | {{ if gt $image.Height $image.Width -}} 9 | {{ $widths = $.Site.Params.portraitPhotoWidths -}} 10 | {{ end -}} 11 | 12 | {{ range $widths -}} 13 | {{ $srcUrl := (printf "%dx" . | $image.Resize).Permalink -}} 14 | {{ if eq $imgSrc "" -}}{{ $imgSrc = $srcUrl -}}{{ end -}} 15 | {{ $imgSrcSet = $imgSrcSet | append (printf "%s %dw" $srcUrl .) -}} 16 | {{ end -}} 17 | {{ $imgSrcSet = (delimit $imgSrcSet ",") -}} 18 | 19 | 20 | {{ if eq .Site.Params.options.lazySizes true -}} 21 | 22 | {{ else -}} 23 | 24 | {{ end -}} 25 | 26 | {{ with .Get "caption" }}
{{ . | safeHTML }}
{{ end }} 27 | 28 | -------------------------------------------------------------------------------- /src/Event.php: -------------------------------------------------------------------------------- 1 | " 20 | url = "https://github.com/darkwood-com/flow" 21 | post = "v0.1.0" 22 | weight = 10 23 | 24 | [[social]] 25 | name = "Twitter" 26 | pre = "" 27 | url = "https://twitter.com/darkwood_com" 28 | weight = 20 29 | 30 | # [[footer]] 31 | # name = "Privacy" 32 | # url = "/privacy-policy/" 33 | # weight = 10 34 | -------------------------------------------------------------------------------- /src/DriverInterface.php: -------------------------------------------------------------------------------- 1 | |Closure(TArgs): void when called this start async $callback. 17 | * 18 | * @param Closure(TArgs): TReturn|JobInterface $callback 19 | */ 20 | public function async(Closure|JobInterface $callback): Closure; 21 | 22 | /** 23 | * This allow more granular control on async 24 | * $callback will be given two callbacks 25 | * - an complete callback to store result 26 | * - an async callback to go to the next async call. 27 | * 28 | * @param Closure(callable(TReturn): void, callable(mixed, callable): void): void $callback 29 | */ 30 | public function defer(Closure $callback): mixed; 31 | 32 | /** 33 | * Waits for all asynchronous operations in the stream to complete and rolls back to synchronous execution. 34 | * 35 | * @param array{'fnFlows': array, 'dispatchers': array} $stream The stream containing asynchronous operations to await 36 | */ 37 | public function await(array &$stream): void; 38 | 39 | public function delay(float $seconds): void; 40 | 41 | /** 42 | * @param float $interval in seconds 43 | * @param Closure(): void $callback 44 | * 45 | * @return Closure(): void when called, this cleanup tick interval 46 | */ 47 | public function tick(float $interval, Closure $callback): Closure; 48 | } 49 | -------------------------------------------------------------------------------- /docs/src/layouts/partials/head/seo.html: -------------------------------------------------------------------------------- 1 | {{ if eq .Kind "404" -}} 2 | 3 | {{ else -}} 4 | {{ with .Params.robots -}} 5 | 6 | {{ else -}} 7 | 8 | 9 | 10 | {{ end -}} 11 | {{ end -}} 12 | 13 | {{ if .IsHome -}} 14 | {{ .Site.Params.title }} {{ .Site.Params.titleSeparator }} {{ .Site.Params.titleAddition }} 15 | {{ else -}} 16 | {{ .Title }} {{ .Site.Params.titleSeparator }} {{ .Site.Params.title }} 17 | {{ end -}} 18 | 19 | {{ with .Description -}} 20 | 21 | {{ else -}} 22 | 23 | {{ end -}} 24 | 25 | {{ if $.Scratch.Get "paginator" }} 26 | 27 | {{ if .Paginator.HasPrev -}} 28 | 29 | {{ end -}} 30 | {{ if .Paginator.HasNext -}} 31 | 32 | {{ end -}} 33 | {{ else -}} 34 | 35 | {{ end -}} 36 | 37 | {{ partial "head/opengraph.html" . }} 38 | {{ partial "head/twitter_cards.html" . }} 39 | 40 | {{ range .AlternativeOutputFormats -}} 41 | 42 | {{ end -}} 43 | 44 | {{ partial "head/structured-data.html" . }} 45 | -------------------------------------------------------------------------------- /docs/src/content/en/docs/getting-started/flow.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Flow" 3 | description: "Flow." 4 | lead: "Flow." 5 | date: 2020-10-13T15:21:01+02:00 6 | lastmod: 2020-10-13T15:21:01+02:00 7 | draft: false 8 | images: [] 9 | menu: 10 | docs: 11 | parent: "getting-started" 12 | weight: 20 13 | toc: true 14 | --- 15 | 16 | # Flow 17 | 18 | ## Flow implementation 19 | 20 | According to [Wikipedia](https://en.wikipedia.org/wiki/Monad_(functional_programming)), Monads is an abstract generic structure that get its usage in function composition. Monads can shortly considered as `Programming with effects`. 21 | 22 | We consider `Flows` as a set of elements in our ensemble as a Monad implementation : 23 | - By using `job` as basic function type within the `Flow`. 24 | - By using `fn` as a binary operation, `Flow` can be composed together with others `Flow` element. 25 | 26 | A `Flow` can process one or many `Ips` which has its application for asynchronous programming when mixing with [`Drivers`](drivers.md). 27 | 28 | ## Flow 29 | 30 | This is the standard Flow implementation that support asynchronous `Ip` processing. 31 | 32 | ## FlowDecorator 33 | 34 | This is useful for implementing the [decorator design pattern](https://en.wikipedia.org/wiki/Decorator_pattern). 35 | 36 | ## TransportFlow 37 | 38 | TransportFlow will interact with Flow with Producer and Sender. 39 | 40 | ## YFlow 41 | 42 | YFlow use YCombinator to provide recursion. 43 | 44 | ## LambdaFlow 45 | 46 | LambdaFlow provides a simple way to create flows using lambda functions or closures. This allows for quick, inline flow definitions without creating separate flow classes. 47 | 48 | ## Make your own Flow 49 | 50 | You can make your custom Flow by implementing `Flow\FlowInterface`. 51 | -------------------------------------------------------------------------------- /docs/src/layouts/rss.xml: -------------------------------------------------------------------------------- 1 | {{ printf "" | safeHTML }} 2 | 3 | 4 | {{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }} 5 | {{ .Permalink }} 6 | Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }} 7 | Hugo -- gohugo.io{{ with .Site.LanguageCode }} 8 | {{.}}{{end}}{{ with .Site.Author.email }} 9 | {{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}}{{ with .Site.Author.email }} 10 | {{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}}{{ with .Site.Params.copyRight }} 11 | {{ . | safeHTML }}{{end}}{{ if not .Date.IsZero }} 12 | {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}{{ end }} 13 | {{ with .OutputFormats.Get "RSS" }} 14 | {{ printf "" .Permalink .MediaType | safeHTML }} 15 | {{ end }} 16 | {{ range .Pages }}{{ if ne .Params.feed_exclude true }} 17 | 18 | {{ .Title }} 19 | {{ .Permalink }} 20 | {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }} 21 | {{ with .Site.Author.email }}{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}} 22 | {{ .Permalink }} 23 | {{ .Summary | html }} 24 | 25 | {{ end }}{{ end }} 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/IpStrategy/MaxIpStrategyTest.php: -------------------------------------------------------------------------------- 1 | push(new PushEvent(new Ip())); 23 | $strategy->push(new PushEvent(new Ip())); 24 | $strategy->push(new PushEvent(new Ip())); 25 | 26 | $ips = []; 27 | 28 | $pullEvent = new PullEvent(); 29 | $strategy->pull($pullEvent); 30 | $ips[] = $pullEvent->getIps()[0] ?? null; 31 | self::assertNotNull($ips[0]); 32 | 33 | $pullEvent = new PullEvent(); 34 | $strategy->pull($pullEvent); 35 | $ips[] = $pullEvent->getIps()[0] ?? null; 36 | self::assertNotNull($ips[1]); 37 | 38 | $pullEvent = new PullEvent(); 39 | $strategy->pull($pullEvent); 40 | $ips[] = $pullEvent->getIps()[0] ?? null; 41 | self::assertNull($ips[2]); 42 | 43 | $strategy->pop(new PopEvent($ips[$doneIndex])); 44 | 45 | $pullEvent = new PullEvent(); 46 | $strategy->pull($pullEvent); 47 | $ips[] = $pullEvent->getIps()[0] ?? null; 48 | self::assertNotNull($ips[3]); 49 | } 50 | 51 | /** 52 | * @return array> 53 | */ 54 | public static function provideStrategyCases(): iterable 55 | { 56 | return [ 57 | [0], 58 | [1], 59 | ]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/AsyncHandler/BatchAsyncHandlerTest.php: -------------------------------------------------------------------------------- 1 | $x, 22 | static fn ($x) => $x, 23 | static function ($data) use (&$result1) { 24 | [$n1, $n2] = $data; 25 | $result1 = $n1 + $n2; 26 | 27 | return static function ($callback) use ($result1) { 28 | $callback($result1); 29 | }; 30 | }, 31 | new Ip([2, 6]), 32 | static function () {} 33 | ); 34 | 35 | $result2 = null; 36 | 37 | $event2 = new AsyncEvent( 38 | static fn ($x) => $x, 39 | static fn ($x) => $x, 40 | static function ($data) use (&$result2) { 41 | [$n1, $n2] = $data; 42 | $result2 = $n1 + $n2; 43 | 44 | return static function ($callback) use ($result2) { 45 | $callback($result2); 46 | }; 47 | }, 48 | new Ip([6, 10]), 49 | static function () {} 50 | ); 51 | 52 | $asyncHandler = new BatchAsyncHandler(2); 53 | $asyncHandler->async($event1); 54 | assertSame(null, $result1); 55 | $asyncHandler->async($event2); 56 | assertSame(8, $result1); 57 | assertSame(16, $result2); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /docs/src/layouts/docs/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 | 7 |
8 | {{ if ne .Params.toc false -}} 9 | 12 | {{ end -}} 13 | {{ if .Params.toc -}} 14 |
15 | {{ else -}} 16 |
17 | {{ end -}} 18 | {{ if .Site.Params.options.breadCrumb -}} 19 | 20 | 26 | {{ end }} 27 | {{/*

{{ .Title }}

28 |

{{ .Params.lead | safeHTML }}

*/}} 29 | {{ if ne .Params.toc false -}} 30 | 33 | {{ end -}} 34 | {{ partial "main/headline-hash.html" .Content }} 35 | {{ if .Site.Params.editPage -}} 36 | {{ partial "main/edit-page.html" . }} 37 | {{ end -}} 38 | {{ partial "main/docs-navigation.html" . }} 39 | 46 |
47 |
48 | {{ end }} -------------------------------------------------------------------------------- /tests/Flow/FlowTrait.php: -------------------------------------------------------------------------------- 1 | > 21 | */ 22 | protected static function matrix(Closure $datas): array 23 | { 24 | $drivers = [ 25 | 'amp' => static fn (): AmpDriver => new AmpDriver(), 26 | 'fiber' => static fn (): FiberDriver => new FiberDriver(), 27 | 'react' => static fn (): ReactDriver => new ReactDriver(), 28 | // 'spatie' => static fn (): SpatieDriver => new SpatieDriver(), 29 | // 'swoole' => static fn (): SwooleDriver => new SwooleDriver(), 30 | ]; 31 | 32 | $strategies = [ 33 | 'linear' => static fn (): LinearIpStrategy => new LinearIpStrategy(), 34 | 'max' => static fn (): MaxIpStrategy => new MaxIpStrategy(), 35 | 'stack' => static fn (): StackIpStrategy => new StackIpStrategy(), 36 | ]; 37 | 38 | $matrixDatas = []; 39 | foreach ($drivers as $keyDriver => $driverBuilder) { 40 | foreach ($strategies as $keyStrategy => $strategyBuilder) { 41 | $driver = $driverBuilder(); 42 | $dataValues = $datas($driver, $strategyBuilder); 43 | foreach ($dataValues as $key => $values) { 44 | $matrixDatas["{$keyDriver}.{$keyStrategy}.{$key}"] = [$driver, ...$values]; 45 | } 46 | } 47 | } 48 | 49 | return $matrixDatas; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/Flow/YFlowTest.php: -------------------------------------------------------------------------------- 1 | $driver 27 | * @param IpStrategyInterface $ipStrategy 28 | */ 29 | public function testJob(DriverInterface $driver, Closure $job, IpStrategyInterface $ipStrategy, int $resultNumber): void 30 | { 31 | $ip = new Ip(new ArrayObject(['number' => 6])); 32 | $errorJob = static function () {}; 33 | $yFlow = (new YFlow($job, $errorJob, $ipStrategy, null, null, $driver)) 34 | ->fn(static function (ArrayObject $data) use ($resultNumber) { 35 | self::assertSame($resultNumber, $data['number']); 36 | }) 37 | ; 38 | $yFlow($ip); 39 | 40 | $yFlow->await(); 41 | } 42 | 43 | /** 44 | * @return array> 45 | */ 46 | public static function provideJobCases(): iterable 47 | { 48 | return self::matrix(static fn (DriverInterface $driver, $strategyBuilder) => [ 49 | 'job' => [static function (callable $factorial): Closure { 50 | return static function (ArrayObject $data) use ($factorial) { 51 | return new ArrayObject([ 52 | 'number' => ($data['number'] <= 1) ? 1 : $data['number'] * $factorial(new ArrayObject(['number' => $data['number'] - 1]))['number'], 53 | ]); 54 | }; 55 | }, $strategyBuilder(), 720], 56 | ]); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /docs/src/layouts/partials/sidebar/docs-menu.html: -------------------------------------------------------------------------------- 1 | {{ if .Site.Params.options.collapsibleSidebar -}} 2 |
    3 | {{ $currentPage := . -}} 4 | {{ range $index, $element := .Site.Menus.docs -}} 5 | {{- $active := or ($currentPage.IsMenuCurrent "docs" .) ($currentPage.HasMenuCurrent "docs" .) -}} 6 | {{- $active = or $active (eq $currentPage.Section .Identifier) -}} 7 |
  • 8 | 11 | {{ if .HasChildren -}} 12 |
    13 |
      14 | {{ range .Children -}} 15 | {{- $active := or ($currentPage.IsMenuCurrent "docs" .) ($currentPage.HasMenuCurrent "docs" .) -}} 16 | {{- $active = or $active (eq $currentPage.Section .Identifier) -}} 17 |
    • {{ .Name }}
    • 18 | {{ end -}} 19 |
    20 |
    21 | {{ end -}} 22 |
  • 23 | {{ end -}} 24 |
25 | {{ else -}} 26 | {{ $currentPage := . -}} 27 | {{ range .Site.Menus.docs -}} 28 |

{{ .Name }}

29 | {{ if .HasChildren -}} 30 |
    31 | {{ range .Children -}} 32 | {{- $active := or ($currentPage.IsMenuCurrent "docs" .) ($currentPage.HasMenuCurrent "docs" .) -}} 33 | {{- $active = or $active (eq $currentPage.Section .Identifier) -}} 34 |
  • {{ .Name }}
  • 35 | {{ end -}} 36 |
37 | {{ end -}} 38 | {{ end -}} 39 | {{ end -}} -------------------------------------------------------------------------------- /tests/Examples/Transport/DoctrineIpTransportTest.php: -------------------------------------------------------------------------------- 1 | 'sqlite:///:memory:']); 21 | $supervisorTransport = new DoctrineIpTransport($connection); 22 | 23 | $clientTransports = []; 24 | for ($i = 0; $i < 5; $i++) { 25 | $clientTransports[] = new DoctrineIpTransport($connection, uniqid('transport_', true)); 26 | } 27 | 28 | for ($i = 0; $i < 20; $i++) { 29 | $data = new ArrayObject(['number' => 1]); 30 | $clientTransports[$i % 5]->send(new Envelope($data)); 31 | } 32 | 33 | $ips = []; 34 | do { 35 | foreach ($ips as $ip) { 36 | $supervisorTransport->ack($ip); 37 | $data = $ip->getMessage(); 38 | self::assertSame(1, $data['number']); 39 | $data['number'] = 2; 40 | $supervisorTransport->send(Envelope::wrap($data, [$ip->last(DoctrineIpTransportIdStamp::class)])); 41 | } 42 | $ips = $supervisorTransport->get(); 43 | } while (count($ips) > 0); 44 | 45 | foreach ($clientTransports as $clientTransport) { 46 | $ips = $clientTransport->get(); 47 | foreach ($ips as $ip) { 48 | $clientTransport->ack($ip); 49 | $data = $ip->getMessage(); 50 | self::assertSame(2, $data['number']); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Flow 4 | 5 |

6 | 7 | ## Why ? 8 | 9 | Flow concept aims to solve 10 | 11 | - Adopt asynchronous as native implementation 12 | - Build your code with functional programming 13 | - Assemble your code visually 14 | 15 | ## Installation 16 | 17 | PHP 8.3 is the minimal version to use Flow 18 | The recommended way to install it through [Composer](http://getcomposer.org) and execute 19 | 20 | ```bash 21 | composer require darkwood/flow 22 | ``` 23 | 24 | ## Usage 25 | 26 | ```php 27 | create(static function() { 50 | yield fn (D1 $data1) => new D2($data1->n1 += 1); 51 | yield fn (D2 $data2) => new D3($data2->n2 * 2); 52 | yield function(D3 $data3) { 53 | printf("my number %d\n", $ip->data->n3)); // display 'my number 10' 54 | 55 | return new D4($data3->n3); 56 | }; 57 | }); 58 | 59 | $ip = new Ip(new D1(4)); 60 | $flow($ip); 61 | $flow->await(); 62 | ``` 63 | 64 | ## Examples 65 | 66 | A working script is available in the bundled `examples` directory 67 | 68 | - Run Flow : `php examples/flow.php` 69 | - Run Y-Combinator Flow : `php examples/yflow.php` 70 | - Start Server : `php examples/server.php` 71 | Start Client(s) : `php examples/client.php` 72 | 73 | ## Documentation 74 | 75 | [https://darkwood-com.github.io/flow](https://darkwood-com.github.io/flow) 76 | 77 | ## License 78 | 79 | Flow is released under the MIT License. 80 | -------------------------------------------------------------------------------- /docs/src/content/en/docs/getting-started/job.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Job" 3 | description: "Job." 4 | lead: "Job." 5 | date: 2020-10-13T15:21:01+02:00 6 | lastmod: 2020-10-13T15:21:01+02:00 7 | draft: false 8 | images: [] 9 | menu: 10 | docs: 11 | parent: "getting-started" 12 | weight: 10 13 | toc: true 14 | --- 15 | 16 | # Job 17 | 18 | When using Flow, you can pass Closure or JobInterface, it's useful when you want to specialize your Job, that come with dependecy injection. 19 | 20 | ## ClosureJob 21 | 22 | ClosureJob simplifies job handling by allowing the use of closures or custom job classes, providing a versatile solution for managing jobs in your application. 23 | 24 | ## YJob 25 | 26 | The YJob class defines the Y combinator to recursively apply the job function, making it particularly useful in scenarios where you need to perform recursive tasks without explicitly writing recursive functions. 27 | 28 | ## LambdaJob 29 | 30 | The LambdaJob class provides a way to evaluate lambda calculus expressions in PHP. It implements the `Flow\JobInterface` and allows you to: 31 | 32 | - Parse and evaluate lambda expressions 33 | - Work with functional programming concepts directly in PHP 34 | - Transform lambda calculus notation into executable PHP code 35 | 36 | Example usage: 37 | 38 | ```php 39 | $ip 16 | */ 17 | public function __invoke(Ip $ip): void; 18 | 19 | /** 20 | * @template T2 21 | * 22 | * @param array|Closure(T1): T2|FlowInterface|JobInterface $flow can be Closure as Job, array constructor arguments for Flow instanciation, array configuration for Flow instanciation or FlowInterface instance 23 | * #param ?array{ 24 | * 0: Closure, 25 | * 1?: Closure, 26 | * 2?: IpStrategyInterface, 27 | * 3?: DriverInterface 28 | * }|array{ 29 | * "job"?: JobInterface|Closure, 30 | * "errorJob"?: JobInterface|Closure, 31 | * "ipStrategy"?: IpStrategyInterface, 32 | * "driver"?: DriverInterface 33 | * }|Closure|FlowInterface $config 34 | * 35 | * @return FlowInterface 36 | */ 37 | public function fn(array|Closure|JobInterface|self $flow): self; 38 | 39 | /** 40 | * Await asynchonous call for current IPs. 41 | * After await, all IPs have been proceed, it continues synchronously. 42 | */ 43 | public function await(): void; 44 | } 45 | -------------------------------------------------------------------------------- /docs/src/layouts/_default/section.sitemap.xml: -------------------------------------------------------------------------------- 1 | {{ printf "" | safeHTML -}} 2 | 4 | {{ range $i, $e := .Data.Pages -}} 5 | {{ if ne .Params.sitemap_exclude true }} 6 | 7 | {{ .Permalink }}{{ if not .Lastmod.IsZero }} 8 | {{ safeHTML ( .Lastmod.Format "2006-01-02T15:04:05-07:00" ) }}{{ end }}{{ with .Sitemap.ChangeFreq }} 9 | {{ . }}{{ end }}{{ if ge .Sitemap.Priority 0.0 }} 10 | {{ .Sitemap.Priority }}{{ end }}{{ if .IsTranslated }}{{ range .Translations }} 11 | {{ end }} 16 | {{ end }} 21 | 22 | {{ end -}} 23 | {{ end -}} 24 | {{ range .Sections -}} 25 | {{ range $i, $e := .Data.Pages -}} 26 | {{ if ne .Params.sitemap_exclude true -}} 27 | 28 | {{ .Permalink }}{{ if not .Lastmod.IsZero }} 29 | {{ safeHTML ( .Lastmod.Format "2006-01-02T15:04:05-07:00" ) }}{{ end }}{{ with .Sitemap.ChangeFreq }} 30 | {{ . }}{{ end }}{{ if ge .Sitemap.Priority 0.0 }} 31 | {{ .Sitemap.Priority }}{{ end }}{{ if .IsTranslated }}{{ range .Translations }} 32 | {{ end }} 37 | {{ end }} 42 | 43 | {{ end -}} 44 | {{ end -}} 45 | {{ end -}} 46 | 47 | -------------------------------------------------------------------------------- /tools/php-cs-fixer/.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | ignoreVCSIgnored(true) 9 | ->ignoreDotFiles(false) 10 | ->in(dirname(__DIR__, 2)) 11 | ->append([ 12 | __FILE__, 13 | ]) 14 | ->notPath('.castor.stub.php') 15 | ; 16 | 17 | return (new Config()) 18 | ->setRiskyAllowed(true) 19 | ->setRules([ 20 | '@PSR12' => true, 21 | '@PHP82Migration' => true, 22 | '@PhpCsFixer' => true, // https://cs.symfony.com/doc/ruleSets/PhpCsFixer.html 23 | '@PhpCsFixer:risky' => true, // https://cs.symfony.com/doc/ruleSets/PhpCsFixerRisky.html 24 | '@PHPUnit100Migration:risky' => true, // https://cs.symfony.com/doc/ruleSets/PHPUnit100MigrationRisky.html 25 | 'heredoc_indentation' => false, 26 | 'php_unit_internal_class' => false, // From @PhpCsFixer but we don't want it 27 | 'php_unit_test_class_requires_covers' => false, // From @PhpCsFixer but we don't want it 28 | 'phpdoc_add_missing_param_annotation' => false, // From @PhpCsFixer but we don't want it 29 | 'phpdoc_to_comment' => false, // We want PHPStan keep pass with anotation line comments 30 | 'concat_space' => ['spacing' => 'one'], 31 | 'ordered_class_elements' => true, // Symfony(PSR12) override the default value, but we don't want 32 | 'blank_line_before_statement' => true, // Symfony(PSR12) override the default value, but we don't want 33 | 'declare_strict_types' => true, // https://cs.symfony.com/doc/rules/strict/declare_strict_types.html 34 | 'global_namespace_import' => [ 35 | 'import_constants' => true, 36 | 'import_functions' => true, 37 | 'import_classes' => true, 38 | ], 39 | 'logical_operators' => false, // https://cs.symfony.com/doc/rules/operator/logical_operators.html prefer use 'or' and 'and' operators by design 40 | 'yoda_style' => false, // https://cs.symfony.com/doc/rules/control_structure/yoda_style.html 41 | 'increment_style' => ['style' => 'post'], 42 | ]) 43 | ->setFinder($finder) 44 | ->setCacheFile(__DIR__ . '/.php-cs-fixer.cache') 45 | ; 46 | -------------------------------------------------------------------------------- /src/Flow/TransportFlow.php: -------------------------------------------------------------------------------- 1 | 22 | */ 23 | class TransportFlow extends FlowDecorator 24 | { 25 | /** 26 | * @var DriverInterface 27 | */ 28 | private DriverInterface $driver; 29 | 30 | /** 31 | * @param null|DriverInterface $driver 32 | */ 33 | public function __construct( 34 | private FlowInterface $flow, 35 | private ReceiverInterface $producer, 36 | private SenderInterface $consumer, 37 | ?DriverInterface $driver = null 38 | ) { 39 | parent::__construct($flow); 40 | $this->fn(function (Envelope $envelope) { 41 | try { 42 | $this->consumer->send(Envelope::wrap($envelope->getMessage(), array_reduce($envelope->all(), static function (array $all, array $stamps) { 43 | foreach ($stamps as $stamp) { 44 | $all[] = $stamp; 45 | } 46 | 47 | return $all; 48 | }, []))); 49 | $this->producer->ack($envelope); 50 | } catch (Exception $e) { 51 | $this->producer->reject($envelope); 52 | } 53 | }); 54 | 55 | $this->driver = $driver ?? new FiberDriver(); 56 | } 57 | 58 | /** 59 | * Producer receive new incoming Ip and initialise their state. 60 | * 61 | * @return Closure when called, this cleanup pull interval 62 | */ 63 | public function pull(int $interval): Closure 64 | { 65 | return $this->driver->tick($interval, function () { 66 | $envelopes = $this->producer->get(); 67 | foreach ($envelopes as $envelope) { 68 | $this->emit($envelope); 69 | } 70 | }); 71 | } 72 | 73 | private function emit(Envelope $envelope): void 74 | { 75 | $ip = new Ip($envelope); 76 | ($this->flow)($ip); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /docs/src/assets/scss/common/_fonts.scss: -------------------------------------------------------------------------------- 1 | /* jost-regular - latin */ 2 | @font-face { 3 | font-family: "Jost"; 4 | font-style: normal; 5 | font-weight: 400; 6 | font-display: swap; 7 | src: 8 | local("Jost"), 9 | url("fonts/vendor/jost/jost-v4-latin-regular.woff2") format("woff2"), 10 | url("fonts/vendor/jost/jost-v4-latin-regular.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 11 | } 12 | 13 | /* jost-500 - latin */ 14 | @font-face { 15 | font-family: "Jost"; 16 | font-style: normal; 17 | font-weight: 500; 18 | font-display: swap; 19 | src: 20 | local("Jost"), 21 | url("fonts/vendor/jost/jost-v4-latin-500.woff2") format("woff2"), 22 | url("fonts/vendor/jost/jost-v4-latin-500.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 23 | } 24 | 25 | /* jost-700 - latin */ 26 | @font-face { 27 | font-family: "Jost"; 28 | font-style: normal; 29 | font-weight: 700; 30 | font-display: swap; 31 | src: 32 | local("Jost"), 33 | url("fonts/vendor/jost/jost-v4-latin-700.woff2") format("woff2"), 34 | url("fonts/vendor/jost/jost-v4-latin-700.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 35 | } 36 | 37 | /* jost-italic - latin */ 38 | @font-face { 39 | font-family: "Jost"; 40 | font-style: italic; 41 | font-weight: 400; 42 | font-display: swap; 43 | src: 44 | local("Jost"), 45 | url("fonts/vendor/jost/jost-v4-latin-italic.woff2") format("woff2"), 46 | url("fonts/vendor/jost/jost-v4-latin-italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 47 | } 48 | 49 | /* jost-500italic - latin */ 50 | @font-face { 51 | font-family: "Jost"; 52 | font-style: italic; 53 | font-weight: 500; 54 | font-display: swap; 55 | src: 56 | local("Jost"), 57 | url("fonts/vendor/jost/jost-v4-latin-500italic.woff2") format("woff2"), 58 | url("fonts/vendor/jost/jost-v4-latin-500italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 59 | } 60 | 61 | /* jost-700italic - latin */ 62 | @font-face { 63 | font-family: "Jost"; 64 | font-style: italic; 65 | font-weight: 700; 66 | font-display: swap; 67 | src: 68 | local("Jost"), 69 | url("fonts/vendor/jost/jost-v4-latin-700italic.woff2") format("woff2"), 70 | url("fonts/vendor/jost/jost-v4-latin-700italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 71 | } 72 | -------------------------------------------------------------------------------- /docs/src/config/_default/config.toml: -------------------------------------------------------------------------------- 1 | baseURL = "https://flow.darkwood.com" 2 | canonifyURLs = false 3 | disableAliases = true 4 | disableHugoGeneratorInject = true 5 | enableEmoji = true 6 | enableGitInfo = false 7 | enableRobotsTXT = true 8 | languageCode = "en-US" 9 | paginate = 7 10 | rssLimit = 10 11 | 12 | # Multilingual 13 | defaultContentLanguage = "en" 14 | disableLanguages = ["de", "nl"] 15 | # defaultContentLanguageInSubdir = true 16 | 17 | # add redirects/headers 18 | [outputs] 19 | home = ["HTML", "RSS", "REDIRECTS", "HEADERS"] 20 | section = ["HTML", "RSS", "SITEMAP"] 21 | 22 | # remove .{ext} from text/netlify 23 | [mediaTypes."text/netlify"] 24 | suffixes = [""] 25 | delimiter = "" 26 | 27 | # add output format for netlify _redirects 28 | [outputFormats.REDIRECTS] 29 | mediaType = "text/netlify" 30 | baseName = "_redirects" 31 | isPlainText = true 32 | notAlternative = true 33 | 34 | # add output format for netlify _headers 35 | [outputFormats.HEADERS] 36 | mediaType = "text/netlify" 37 | baseName = "_headers" 38 | isPlainText = true 39 | notAlternative = true 40 | 41 | # add output format for section sitemap.xml 42 | [outputFormats.SITEMAP] 43 | mediaType = "application/xml" 44 | baseName = "sitemap" 45 | isHTML = false 46 | isPlainText = true 47 | noUgly = true 48 | rel = "sitemap" 49 | 50 | [caches] 51 | [caches.getjson] 52 | dir = ":cacheDir/:project" 53 | maxAge = "10s" 54 | 55 | [sitemap] 56 | changefreq = "weekly" 57 | filename = "sitemap.xml" 58 | priority = 0.5 59 | 60 | [taxonomies] 61 | contributor = "contributors" 62 | 63 | [permalinks] 64 | blog = "/blog/:title/" 65 | 66 | [minify.tdewolff.html] 67 | keepWhitespace = false 68 | 69 | [module] 70 | [module.hugoVersion] 71 | extended = true 72 | min = "0.80.0" 73 | max = "" 74 | [[module.mounts]] 75 | source = "assets" 76 | target = "assets" 77 | [[module.mounts]] 78 | source = "static" 79 | target = "static" 80 | [[module.mounts]] 81 | source = "../node_modules/flexsearch" 82 | target = "assets/js/vendor/flexsearch" 83 | [[module.mounts]] 84 | source = "../node_modules/katex" 85 | target = "assets/js/vendor/katex" 86 | [[module.mounts]] 87 | source = "../node_modules/mermaid" 88 | target = "assets/js/vendor/mermaid" 89 | 90 | [deployment] 91 | order = [".jpg$", ".gif$"] 92 | 93 | [[deployment.targets]] 94 | name = "github" 95 | URL = "https://flow.darkwood.com" 96 | branch = "gh-pages" 97 | -------------------------------------------------------------------------------- /docs/src/content/en/privacy-policy/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Privacy Policy" 3 | description: "We do not use cookies and we do not collect any personal data." 4 | date: 2020-08-27T19:23:18+02:00 5 | lastmod: 2020-08-27T19:23:18+02:00 6 | draft: true 7 | images: [] 8 | --- 9 | 10 | __TLDR__: We do not use cookies and we do not collect any personal data. 11 | 12 | ## Website visitors 13 | 14 | - No personal information is collected. 15 | - No information is stored in the browser. 16 | - No information is shared with, sent to or sold to third-parties. 17 | - No information is shared with advertising companies. 18 | - No information is mined and harvested for personal and behavioral trends. 19 | - No information is monetized. 20 | 21 | ### Information we collect and what we use it for 22 | 23 | We run [Matomo](https://matomo.org/) analytics on darkwood-com.github.io. The following information is collected: 24 | 25 | - __Page URL__. We track the page URL of each page view on this website. We use this to understand which pages have been viewed and how many times a particular page has been viewed. For example: _https://darkwood-com.github.io/flow/_. 26 | - __HTTP Referrer__. We use the referrer string to understand the number of visitors referred to this website from links on other sites. For example: _https://github.com/_. 27 | - __Browser__. We use this to understand what browsers people use when visiting this website. This is derived from the User-Agent HTTP header. The full User-Agent is discarded. For example: _Brave_. 28 | - __Operating system__. We use this to understand what operating systems people use when visiting this website. We only use the brand of the operating system and don’t include the version number or any other details. This is derived from the User-Agent HTTP header. The full User-Agent is discarded. For example: _GNU/Linux_. 29 | - __Device type__. We use this to understand what devices people use when visiting this website. This is derived from window.innerWidth. The actual width of the browser in pixels is discarded. For example: _Desktop_. 30 | - __Visitor Country__. We look up the visitor’s country using the IP address. We do not track anything more granular than the country of origin and the IP address of the visitor is discarded. We never store IP addresses in our database or logs. For example: _Canada_. 31 | 32 | ## Contact us 33 | 34 | [Contact us]({{< relref "contact/index.md" >}}) if you have any questions. 35 | 36 | Effective Date: _27th August 2020_ 37 | -------------------------------------------------------------------------------- /tools/editorconfig-fixer/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "8c6f1188e62d626d69d848fb5c7b2293", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "tomasvotruba/editorconfig-fixer", 12 | "version": "0.1.2", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/TomasVotruba/editorconfig-fixer.git", 16 | "reference": "b3a64e0f0eca63d37d870af08184c72e966353ef" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/TomasVotruba/editorconfig-fixer/zipball/b3a64e0f0eca63d37d870af08184c72e966353ef", 21 | "reference": "b3a64e0f0eca63d37d870af08184c72e966353ef", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": ">=7.2" 26 | }, 27 | "bin": [ 28 | "bin/editorconfig-fixer", 29 | "bin/editorconfig-fixer.php" 30 | ], 31 | "type": "library", 32 | "notification-url": "https://packagist.org/downloads/", 33 | "license": [ 34 | "MIT" 35 | ], 36 | "description": "Fix your files indent based on .editorconfig", 37 | "support": { 38 | "issues": "https://github.com/TomasVotruba/editorconfig-fixer/issues", 39 | "source": "https://github.com/TomasVotruba/editorconfig-fixer/tree/0.1.2" 40 | }, 41 | "funding": [ 42 | { 43 | "url": "https://www.paypal.me/rectorphp", 44 | "type": "custom" 45 | }, 46 | { 47 | "url": "https://github.com/tomasvotruba", 48 | "type": "github" 49 | } 50 | ], 51 | "time": "2023-09-26T11:01:15+00:00" 52 | } 53 | ], 54 | "aliases": [], 55 | "minimum-stability": "stable", 56 | "stability-flags": [], 57 | "prefer-stable": false, 58 | "prefer-lowest": false, 59 | "platform": [], 60 | "platform-dev": [], 61 | "plugin-api-version": "2.3.0" 62 | } 63 | -------------------------------------------------------------------------------- /docs/src/assets/scss/layouts/_sidebar.scss: -------------------------------------------------------------------------------- 1 | .docs-links, 2 | .docs-toc { 3 | scrollbar-width: thin; 4 | scrollbar-color: $white $white; 5 | } 6 | 7 | .docs-links::-webkit-scrollbar, 8 | .docs-toc::-webkit-scrollbar { 9 | width: 5px; 10 | } 11 | 12 | .docs-links::-webkit-scrollbar-track, 13 | .docs-toc::-webkit-scrollbar-track { 14 | background: $white; 15 | } 16 | 17 | .docs-links::-webkit-scrollbar-thumb, 18 | .docs-toc::-webkit-scrollbar-thumb { 19 | background: $white; 20 | } 21 | 22 | .docs-links:hover, 23 | .docs-toc:hover { 24 | scrollbar-width: thin; 25 | scrollbar-color: $gray-200 $white; 26 | } 27 | 28 | .docs-links:hover::-webkit-scrollbar-thumb, 29 | .docs-toc:hover::-webkit-scrollbar-thumb { 30 | background: $gray-200; 31 | } 32 | 33 | .docs-links::-webkit-scrollbar-thumb:hover, 34 | .docs-toc::-webkit-scrollbar-thumb:hover { 35 | background: $gray-200; 36 | } 37 | 38 | .docs-links h3, 39 | .page-links h3 { 40 | text-transform: uppercase; 41 | font-size: $font-size-base; 42 | margin: 1.25rem 0 0.5rem 0; 43 | padding: 1.5rem 0 0 0; 44 | } 45 | 46 | @include media-breakpoint-up(lg) { 47 | .docs-links h3, 48 | .page-links h3 { 49 | margin: 1.125rem 1.5rem 0.75rem 0; 50 | padding: 1.375rem 0 0 0; 51 | } 52 | } 53 | 54 | .docs-links h3:not(:first-child) { 55 | border-top: 1px solid $gray-200; 56 | } 57 | 58 | a.docs-link { 59 | color: $body-color; 60 | display: block; 61 | padding: 0.125rem 0; 62 | font-size: $font-size-base; 63 | } 64 | 65 | .page-links li { 66 | margin-top: 0.375rem; 67 | padding-top: 0.375rem; 68 | } 69 | 70 | .page-links li ul li { 71 | border-top: none; 72 | padding-left: 1rem; 73 | margin-top: 0.125rem; 74 | padding-top: 0.125rem; 75 | } 76 | 77 | .page-links li:not(:first-child) { 78 | border-top: 1px dashed $gray-200; 79 | } 80 | 81 | .page-links a { 82 | color: $body-color; 83 | display: block; 84 | padding: 0.125rem 0; 85 | font-size: $font-size-base * 0.9375; 86 | } 87 | 88 | .docs-link:hover, 89 | .docs-link.active, 90 | .page-links a:hover { 91 | text-decoration: none; 92 | color: $link-color; 93 | } 94 | 95 | .docs-links h3.sidebar-link, 96 | .page-links h3.sidebar-link { 97 | text-transform: none; 98 | font-size: $font-size-md; 99 | font-weight: normal; 100 | } 101 | 102 | .docs-links h3.sidebar-link a, 103 | .page-links h3.sidebar-link a { 104 | color: $body-color; 105 | } 106 | 107 | .docs-links h3.sidebar-link a:hover, 108 | .page-links h3.sidebar-link a:hover { 109 | text-decoration: underline; 110 | } 111 | -------------------------------------------------------------------------------- /src/AsyncHandler/BatchAsyncHandler.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | final class BatchAsyncHandler implements BatchHandlerInterface, AsyncHandlerInterface 22 | { 23 | use BatchHandlerTrait; 24 | 25 | /** 26 | * @var AsyncHandlerInterface 27 | */ 28 | private AsyncHandlerInterface $asyncHandler; 29 | 30 | /** 31 | * @param null|AsyncHandlerInterface $asyncHandler 32 | */ 33 | public function __construct( 34 | private int $batchSize = 10, 35 | ?AsyncHandlerInterface $asyncHandler = null, 36 | ) { 37 | $this->asyncHandler = $asyncHandler ?? new AsyncHandler(); 38 | } 39 | 40 | public static function getSubscribedEvents() 41 | { 42 | return [ 43 | Event::ASYNC => 'async', 44 | Event::POOL => 'pool', 45 | ]; 46 | } 47 | 48 | public function async(AsyncEvent $event): void 49 | { 50 | $ack = new Acknowledger(get_debug_type($this), function (?Throwable $e = null, $event = null) { 51 | $this->asyncHandler->async($event); 52 | }); 53 | 54 | $this->handle($event, $ack); 55 | } 56 | 57 | public function pool(PoolEvent $event): void 58 | { 59 | $this->asyncHandler->pool($event); 60 | } 61 | 62 | /** 63 | * PHPStan should normaly pass for method.unused 64 | * https://github.com/phpstan/phpstan/issues/6039 65 | * https://phpstan.org/r/8f7de023-9888-4dcb-b12c-e2fcf9547b6c. 66 | * 67 | * @param array{0: AsyncEvent, 1: Acknowledger}[] $jobs 68 | * 69 | * @phpstan-ignore method.unused 70 | */ 71 | private function process(array $jobs): void 72 | { 73 | foreach ($jobs as [$event, $ack]) { 74 | $ack->ack($event); 75 | } 76 | } 77 | 78 | /** 79 | * PHPStan should normaly pass for method.unused 80 | * https://github.com/phpstan/phpstan/issues/6039 81 | * https://phpstan.org/r/8f7de023-9888-4dcb-b12c-e2fcf9547b6c. 82 | * 83 | * @phpstan-ignore method.unused 84 | */ 85 | private function getBatchSize(): int 86 | { 87 | return $this->batchSize; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | First of all, **thank you** for contributing, **you are awesome**! 4 | 5 | Everybody should be able to help. Here's how you can do it 6 | 7 | - [Fork it](https://github.com/darkwood-com/flow/fork) 8 | - Improve it 9 | - Submit a [pull request](https://help.github.com/articles/creating-a-pull-request) 10 | 11 | Here's some tips to make you the best contributor ever 12 | 13 | - [Bug reports](#bug-reports) 14 | - [Feature requests](#feature-requests) 15 | - [Creating a pull request](#creating-a-pull-request) 16 | - [Coding standard](#coding-standard) 17 | 18 | ## Bug reports 19 | 20 | Please search existing issues first to make sure this is not a duplicate. 21 | Every issue report has a cost for the developers required to field it; be 22 | respectful of others' time and ensure your report isn't spurious prior to 23 | submission. Try to be as detailed as possible in your problem description 24 | to help us fix the bug. Please adhere to 25 | [sound bug reporting principles](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html). 26 | 27 | ## Feature requests 28 | 29 | If you wish to propose a feature, please submit an issue. Try to explain your 30 | use case as fully as possible to help us understand why you think the feature 31 | should be added. 32 | 33 | ## Creating a pull request 34 | 35 | First [fork the repository](https://help.github.com/articles/fork-a-repo/) on 36 | GitHub. 37 | 38 | Then clone your fork: 39 | 40 | ```bash 41 | git clone git@github.com:darkwood-com/flow.git 42 | git checkout -b bug-or-feature-description 43 | ``` 44 | 45 | And install the dependencies: 46 | 47 | ```bash 48 | composer install 49 | ``` 50 | 51 | Write your code and add tests. Then run the tests: 52 | 53 | ```bash 54 | make test 55 | ``` 56 | 57 | Commit your changes and push them to GitHub: 58 | 59 | ```bash 60 | git commit -m ":sparkles: Introduce awesome new feature" 61 | git push -u origin bug-or-feature-description 62 | ``` 63 | 64 | Then [create a pull request](https://help.github.com/articles/creating-a-pull-request/) 65 | on GitHub. 66 | 67 | If you need to make some changes, commit and push them as you like. When asked 68 | to squash your commits, do so as follows: 69 | 70 | ```bash 71 | git rebase -i 72 | git push origin bug-or-feature-description -f 73 | ``` 74 | 75 | ## Coding standard 76 | 77 | This project follows the [Symfony](https://symfony.com/doc/current/contributing/code/standards.html) coding style. 78 | Please make sure your pull requests adhere to this standard. 79 | 80 | To fix, execute this command after [download PHP CS Fixer](https://cs.symfony.com/): 81 | 82 | ```bash 83 | make php-cs-fixer 84 | ``` 85 | -------------------------------------------------------------------------------- /docs/src/config/_default/params.toml: -------------------------------------------------------------------------------- 1 | # Meta Data for SEO 2 | 3 | ## Homepage 4 | title = "Flow" 5 | titleSeparator = "-" 6 | titleAddition = "Flow" 7 | description = "Assemble your code by adopting asynchronous as native implementation and build with functional programming and monads." 8 | 9 | ## Open Graph 10 | images = ["flow.png"] 11 | ogLocale = "en_US" 12 | domainTLD = "darkwood-com.github.io" 13 | titleHome = "Doks Theme" 14 | 15 | ## Twitter Cards 16 | twitterSite = "@darkwood_com" 17 | twitterCreator = "@matyo91" 18 | 19 | ## JSON-LD 20 | # schemaType = "Person" 21 | schemaType = "Organization" 22 | schemaName = "Darkwood" 23 | schemaAuthor = "Mathieu Ledru" 24 | schemaAuthorTwitter = "https://twitter.com/matyo91" 25 | schemaAuthorLinkedIn = "https://www.linkedin.com/in/mathieu-ledru/" 26 | schemaAuthorGitHub = "https://github.com/matyo91" 27 | schemaLocale = "en-US" 28 | schemaLogo = "logo-flow.png" 29 | schemaLogoWidth = 512 30 | schemaLogoHeight = 512 31 | schemaImage = "flow.png" 32 | schemaImageWidth = 1280 33 | schemaImageHeight = 640 34 | schemaTwitter = "https://twitter.com/darkwood_com" 35 | schemaLinkedIn = "" 36 | schemaGitHub = "https://github.com/darkwood-com/flow" 37 | schemaSection = "blog" 38 | 39 | ## Sitelinks Search Box 40 | siteLinksSearchBox = false 41 | 42 | ## Chrome Browser 43 | themeColor = "#fff" 44 | 45 | # Images 46 | quality = 85 47 | bgColor = "#fff" 48 | landscapePhotoWidths = [900, 800, 700, 600, 500] 49 | portraitPhotoWidths = [800, 700, 600, 500] 50 | lqipWidth = "20x" 51 | 52 | # Footer 53 | footer = "Powered by Github Pages, Hugo, and Doks" 54 | 55 | # Feed 56 | copyRight = "Copyright (c) 2021 Darkwood" 57 | 58 | # Alert 59 | alert = false 60 | alertDismissable = true 61 | # alertText = "Introducing the Doks child theme, several DX + UX updates, and more! Check out Doks v0.2" 62 | alertText = "Introducing the Doks child theme, several DX + UX updates, and more! Check out Doks v0.2" 63 | 64 | # Edit Page 65 | docsRepo = "https://github.com/darkwood-com/flow" 66 | editPage = true 67 | 68 | [options] 69 | lazySizes = true 70 | clipBoard = true 71 | instantPage = true 72 | flexSearch = true 73 | darkMode = true 74 | bootStrapJs = true 75 | breadCrumb = false 76 | highLight = true 77 | kaTex = false 78 | collapsibleSidebar = true 79 | multilingualMode = false 80 | docsVersioning = false # Not yet functional 81 | --------------------------------------------------------------------------------