├── .env ├── .gitignore ├── LICENSE ├── README.md ├── bin └── console ├── composer.json ├── composer.lock ├── config ├── bundles.php ├── packages │ ├── cache.yaml │ ├── dev │ │ ├── debug.yaml │ │ ├── monolog.yaml │ │ ├── routing.yaml │ │ └── web_profiler.yaml │ ├── framework.yaml │ ├── gos_web_socket.php │ ├── prod │ │ ├── deprecations.yaml │ │ ├── monolog.yaml │ │ └── routing.yaml │ ├── routing.yaml │ ├── security.yaml │ ├── test │ │ ├── monolog.yaml │ │ ├── routing.yaml │ │ ├── twig.yaml │ │ └── web_profiler.yaml │ └── twig.yaml ├── preload.php ├── pubsub │ └── websocket │ │ └── example.php ├── routes.yaml ├── routes │ ├── annotations.yaml │ ├── dev │ │ └── web_profiler.yaml │ └── framework.yaml ├── secrets │ └── prod │ │ └── .gitignore └── services.yaml ├── public ├── .htaccess └── index.php ├── src ├── Controller │ ├── .gitignore │ └── HomepageController.php ├── Kernel.php └── Websocket │ ├── Rpc │ └── AcmeRpc.php │ └── Topic │ └── AcmeTopic.php ├── symfony.lock ├── templates ├── base.html.twig └── homepage.html.twig └── var └── cache └── .gitkeep /.env: -------------------------------------------------------------------------------- 1 | # In all environments, the following files are loaded if they exist, 2 | # the latter taking precedence over the former: 3 | # 4 | # * .env contains default values for the environment variables needed by the app 5 | # * .env.local uncommitted file with local overrides 6 | # * .env.$APP_ENV committed environment-specific defaults 7 | # * .env.$APP_ENV.local uncommitted environment-specific overrides 8 | # 9 | # Real environment variables win over .env files. 10 | # 11 | # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. 12 | # 13 | # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). 14 | # https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration 15 | 16 | ###> symfony/framework-bundle ### 17 | APP_ENV=dev 18 | APP_SECRET=0f3e0e5d600a418c3330b7318b094fcc 19 | ###< symfony/framework-bundle ### 20 | 21 | ###> gos/web-socket-bundle ### 22 | GOS_WEB_SOCKET_SERVER_IP=127.0.0.1 23 | GOS_WEB_SOCKET_SERVER_PORT=1337 24 | ###< gos/web-socket-bundle ### 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###> symfony/framework-bundle ### 2 | /.env.local 3 | /.env.local.php 4 | /.env.*.local 5 | /config/secrets/prod/prod.decrypt.private.php 6 | /public/bundles/ 7 | /var/ 8 | /vendor/ 9 | ###< symfony/framework-bundle ### 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Johann Saunier 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GosWebSocketBundle Demo 2 | ======================= 3 | 4 | This is a demo application based on a stripped down version of the [Symfony website skeleton](https://github.com/symfony/website-skeleton). To test this demo: 5 | 6 | - Clone this repository to your test server (`git clone git@github.com:GeniusesOfSymfony/WebsocketAppDemo.git`) 7 | - Enter the directory where you cloned this demo app (i.e. `cd WebsocketAppDemo`) 8 | - Optional: Check out the branch you wish to use: 9 | - Use the `1.x` branch for GosWebSocketBundle 1.x 10 | - Use the `2.x` branch for GosWebSocketBundle 2.x 11 | - Use the `master` branch for GosWebSocketBundle 3.x 12 | - Run `composer install` to install all dependencies 13 | - Start the websocket server with the `php bin/console gos:websocket:server` command 14 | - Visit the app's homepage in your browser 15 | - Check the browser's console log 16 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | ['all' => true], 5 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], 6 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], 7 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], 8 | Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], 9 | Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true], 10 | Gos\Bundle\PubSubRouterBundle\GosPubSubRouterBundle::class => ['all' => true], 11 | Gos\Bundle\WebSocketBundle\GosWebSocketBundle::class => ['all' => true], 12 | ]; 13 | -------------------------------------------------------------------------------- /config/packages/cache.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | cache: 3 | # Unique name of your app: used to compute stable namespaces for cache keys. 4 | #prefix_seed: your_vendor_name/app_name 5 | 6 | # The "app" cache stores to the filesystem by default. 7 | # The data in this cache should persist between deploys. 8 | # Other options include: 9 | 10 | # Redis 11 | #app: cache.adapter.redis 12 | #default_redis_provider: redis://localhost 13 | 14 | # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) 15 | #app: cache.adapter.apcu 16 | 17 | # Namespaced pools use the above "app" backend by default 18 | #pools: 19 | #my.dedicated.cache: null 20 | -------------------------------------------------------------------------------- /config/packages/dev/debug.yaml: -------------------------------------------------------------------------------- 1 | debug: 2 | # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser. 3 | # See the "server:dump" command to start a new server. 4 | dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%" 5 | -------------------------------------------------------------------------------- /config/packages/dev/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: stream 5 | path: "%kernel.logs_dir%/%kernel.environment%.log" 6 | level: debug 7 | channels: ["!event"] 8 | # uncomment to get logging in your browser 9 | # you may have to allow bigger header sizes in your Web server configuration 10 | #firephp: 11 | # type: firephp 12 | # level: info 13 | #chromephp: 14 | # type: chromephp 15 | # level: info 16 | console: 17 | type: console 18 | process_psr_3_messages: false 19 | channels: ["!event", "!doctrine", "!console"] 20 | -------------------------------------------------------------------------------- /config/packages/dev/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: true 4 | -------------------------------------------------------------------------------- /config/packages/dev/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler: 2 | toolbar: true 3 | intercept_redirects: false 4 | 5 | framework: 6 | profiler: { only_exceptions: false } 7 | -------------------------------------------------------------------------------- /config/packages/framework.yaml: -------------------------------------------------------------------------------- 1 | # see https://symfony.com/doc/current/reference/configuration/framework.html 2 | framework: 3 | secret: '%env(APP_SECRET)%' 4 | #csrf_protection: true 5 | http_method_override: false 6 | 7 | # Enables session support. Note that the session will ONLY be started if you read or write from it. 8 | # Remove or comment this section to explicitly disable session support. 9 | session: 10 | handler_id: null 11 | cookie_secure: auto 12 | cookie_samesite: lax 13 | storage_factory_id: session.storage.factory.native 14 | 15 | #esi: true 16 | #fragments: true 17 | php_errors: 18 | log: true 19 | 20 | when@test: 21 | framework: 22 | test: true 23 | session: 24 | storage_factory_id: session.storage.factory.mock_file 25 | -------------------------------------------------------------------------------- /config/packages/gos_web_socket.php: -------------------------------------------------------------------------------- 1 | server() 8 | ->port('%env(int:GOS_WEB_SOCKET_SERVER_PORT)%') 9 | ->host('%env(GOS_WEB_SOCKET_SERVER_IP)%') 10 | ->router() 11 | ->resources(['resource' => '%kernel.project_dir%/config/pubsub/websocket/*', 'type' => 'glob']) 12 | 13 | ; 14 | }; 15 | -------------------------------------------------------------------------------- /config/packages/prod/deprecations.yaml: -------------------------------------------------------------------------------- 1 | # As of Symfony 5.1, deprecations are logged in the dedicated "deprecation" channel when it exists 2 | #monolog: 3 | # channels: [deprecation] 4 | # handlers: 5 | # deprecation: 6 | # type: stream 7 | # channels: [deprecation] 8 | # path: php://stderr 9 | -------------------------------------------------------------------------------- /config/packages/prod/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: fingers_crossed 5 | action_level: error 6 | handler: nested 7 | excluded_http_codes: [404, 405] 8 | buffer_size: 50 # How many messages should be saved? Prevent memory leaks 9 | nested: 10 | type: stream 11 | path: php://stderr 12 | level: debug 13 | formatter: monolog.formatter.json 14 | console: 15 | type: console 16 | process_psr_3_messages: false 17 | channels: ["!event", "!doctrine"] 18 | -------------------------------------------------------------------------------- /config/packages/prod/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: null 4 | -------------------------------------------------------------------------------- /config/packages/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | utf8: true 4 | 5 | # Configure how to generate URLs in non-HTTP contexts, such as CLI commands. 6 | # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands 7 | #default_uri: http://localhost 8 | -------------------------------------------------------------------------------- /config/packages/security.yaml: -------------------------------------------------------------------------------- 1 | security: 2 | enable_authenticator_manager: true 3 | # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers 4 | providers: 5 | users_in_memory: { memory: null } 6 | firewalls: 7 | dev: 8 | pattern: ^/(_(profiler|wdt)|css|images|js)/ 9 | security: false 10 | main: 11 | lazy: true 12 | provider: users_in_memory 13 | 14 | # activate different ways to authenticate 15 | # https://symfony.com/doc/current/security.html#firewalls-authentication 16 | 17 | # https://symfony.com/doc/current/security/impersonating_user.html 18 | # switch_user: true 19 | 20 | # Easy way to control access for large sections of your site 21 | # Note: Only the *first* access control that matches will be used 22 | access_control: 23 | # - { path: ^/admin, roles: ROLE_ADMIN } 24 | # - { path: ^/profile, roles: ROLE_USER } 25 | -------------------------------------------------------------------------------- /config/packages/test/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: fingers_crossed 5 | action_level: error 6 | handler: nested 7 | excluded_http_codes: [404, 405] 8 | channels: ["!event"] 9 | nested: 10 | type: stream 11 | path: "%kernel.logs_dir%/%kernel.environment%.log" 12 | level: debug 13 | -------------------------------------------------------------------------------- /config/packages/test/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: true 4 | -------------------------------------------------------------------------------- /config/packages/test/twig.yaml: -------------------------------------------------------------------------------- 1 | twig: 2 | strict_variables: true 3 | -------------------------------------------------------------------------------- /config/packages/test/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler: 2 | toolbar: false 3 | intercept_redirects: false 4 | 5 | framework: 6 | profiler: { collect: false } 7 | -------------------------------------------------------------------------------- /config/packages/twig.yaml: -------------------------------------------------------------------------------- 1 | twig: 2 | default_path: '%kernel.project_dir%/templates' 3 | -------------------------------------------------------------------------------- /config/preload.php: -------------------------------------------------------------------------------- 1 | collection(); 7 | 8 | $collection->add('acme_topic', 'acme/channel', 'acme.topic'); 9 | 10 | $collection->add('acme_rpc', 'sample/{method}', 'acme.rpc') 11 | ->requirements( 12 | [ 13 | 'method' => '[a-z_]+', 14 | ] 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /config/routes.yaml: -------------------------------------------------------------------------------- 1 | #index: 2 | # path: / 3 | # controller: App\Controller\DefaultController::index 4 | -------------------------------------------------------------------------------- /config/routes/annotations.yaml: -------------------------------------------------------------------------------- 1 | controllers: 2 | resource: ../../src/Controller/ 3 | type: annotation 4 | 5 | kernel: 6 | resource: ../../src/Kernel.php 7 | type: annotation 8 | -------------------------------------------------------------------------------- /config/routes/dev/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler_wdt: 2 | resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' 3 | prefix: /_wdt 4 | 5 | web_profiler_profiler: 6 | resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' 7 | prefix: /_profiler 8 | -------------------------------------------------------------------------------- /config/routes/framework.yaml: -------------------------------------------------------------------------------- 1 | when@dev: 2 | _errors: 3 | resource: '@FrameworkBundle/Resources/config/routing/errors.xml' 4 | prefix: /_error 5 | -------------------------------------------------------------------------------- /config/secrets/prod/.gitignore: -------------------------------------------------------------------------------- 1 | /prod.decrypt.private.php 2 | -------------------------------------------------------------------------------- /config/services.yaml: -------------------------------------------------------------------------------- 1 | # This file is the entry point to configure your own services. 2 | # Files in the packages/ subdirectory configure your dependencies. 3 | 4 | # Put parameters here that don't need to change on each machine where the app is deployed 5 | # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration 6 | parameters: 7 | # Adds fallback params in case the corresponding env vars are not set. 8 | # This allows you to run cache:warmup even if your 9 | # environment variables are not available yet. 10 | # You should not need to change this value. 11 | env(GOS_WEB_SOCKET_SERVER_IP): '127.0.0.1' 12 | env(GOS_WEB_SOCKET_SERVER_PORT): 1337 13 | 14 | services: 15 | # default configuration for services in *this* file 16 | _defaults: 17 | autowire: true # Automatically injects dependencies in your services. 18 | autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. 19 | 20 | # makes classes in src/ available to be used as services 21 | # this creates a service per class whose id is the fully-qualified class name 22 | App\: 23 | resource: '../src/' 24 | exclude: 25 | - '../src/DependencyInjection/' 26 | - '../src/Entity/' 27 | - '../src/Kernel.php' 28 | - '../src/Tests/' 29 | 30 | # add more service definitions when explicit configuration is needed 31 | # please note that last definitions always *replace* previous ones 32 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | # Use the front controller as index file. It serves as a fallback solution when 2 | # every other rewrite/redirect fails (e.g. in an aliased environment without 3 | # mod_rewrite). Additionally, this reduces the matching process for the 4 | # start page (path "/") because otherwise Apache will apply the rewriting rules 5 | # to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl). 6 | DirectoryIndex index.php 7 | 8 | # By default, Apache does not evaluate symbolic links if you did not enable this 9 | # feature in your server configuration. Uncomment the following line if you 10 | # install assets as symlinks or if you experience problems related to symlinks 11 | # when compiling LESS/Sass/CoffeScript assets. 12 | # Options +FollowSymlinks 13 | 14 | # Disabling MultiViews prevents unwanted negotiation, e.g. "/index" should not resolve 15 | # to the front controller "/index.php" but be rewritten to "/index.php/index". 16 | 17 | Options -MultiViews 18 | 19 | 20 | 21 | RewriteEngine On 22 | 23 | # Determine the RewriteBase automatically and set it as environment variable. 24 | # If you are using Apache aliases to do mass virtual hosting or installed the 25 | # project in a subdirectory, the base path will be prepended to allow proper 26 | # resolution of the index.php file and to redirect to the correct URI. It will 27 | # work in environments without path prefix as well, providing a safe, one-size 28 | # fits all solution. But as you do not need it in this case, you can comment 29 | # the following 2 lines to eliminate the overhead. 30 | RewriteCond %{REQUEST_URI}::$0 ^(/.+)/(.*)::\2$ 31 | RewriteRule .* - [E=BASE:%1] 32 | 33 | # Sets the HTTP_AUTHORIZATION header removed by Apache 34 | RewriteCond %{HTTP:Authorization} .+ 35 | RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0] 36 | 37 | # Redirect to URI without front controller to prevent duplicate content 38 | # (with and without `/index.php`). Only do this redirect on the initial 39 | # rewrite by Apache and not on subsequent cycles. Otherwise we would get an 40 | # endless redirect loop (request -> rewrite to front controller -> 41 | # redirect -> request -> ...). 42 | # So in case you get a "too many redirects" error or you always get redirected 43 | # to the start page because your Apache does not expose the REDIRECT_STATUS 44 | # environment variable, you have 2 choices: 45 | # - disable this feature by commenting the following 2 lines or 46 | # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the 47 | # following RewriteCond (best solution) 48 | RewriteCond %{ENV:REDIRECT_STATUS} ="" 49 | RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L] 50 | 51 | # If the requested filename exists, simply serve it. 52 | # We only want to let Apache serve files and not directories. 53 | # Rewrite all other queries to the front controller. 54 | RewriteCond %{REQUEST_FILENAME} !-f 55 | RewriteRule ^ %{ENV:BASE}/index.php [L] 56 | 57 | 58 | 59 | 60 | # When mod_rewrite is not available, we instruct a temporary redirect of 61 | # the start page to the front controller explicitly so that the website 62 | # and the generated links can still be used. 63 | RedirectMatch 307 ^/$ /index.php/ 64 | # RedirectTemp cannot be used instead 65 | 66 | 67 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | render('homepage.html.twig'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Kernel.php: -------------------------------------------------------------------------------- 1 | import('../config/{packages}/*.{php,yaml}'); 17 | $container->import('../config/{packages}/'.$this->environment.'/*.{php,yaml}'); 18 | 19 | if (is_file(\dirname(__DIR__).'/config/services.yaml')) { 20 | $container->import('../config/services.yaml'); 21 | $container->import('../config/{services}_'.$this->environment.'.yaml'); 22 | } elseif (is_file($path = \dirname(__DIR__).'/config/services.php')) { 23 | (require $path)($container->withPath($path), $this); 24 | } 25 | } 26 | 27 | protected function configureRoutes(RoutingConfigurator $routes): void 28 | { 29 | $routes->import('../config/{routes}/'.$this->environment.'/*.yaml'); 30 | $routes->import('../config/{routes}/*.yaml'); 31 | 32 | if (is_file(\dirname(__DIR__).'/config/routes.yaml')) { 33 | $routes->import('../config/routes.yaml'); 34 | } elseif (is_file($path = \dirname(__DIR__).'/config/routes.php')) { 35 | (require $path)($routes->withPath($path), $this); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Websocket/Rpc/AcmeRpc.php: -------------------------------------------------------------------------------- 1 | array_sum($params)]; 14 | } 15 | 16 | public function getName(): string 17 | { 18 | return 'acme.rpc'; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Websocket/Topic/AcmeTopic.php: -------------------------------------------------------------------------------- 1 | broadcast(['msg' => $connection->resourceId.' has joined '.$topic->getId()]); 16 | } 17 | 18 | public function onUnSubscribe(ConnectionInterface $connection, Topic $topic, WampRequest $request): void 19 | { 20 | //this will broadcast the message to ALL subscribers of this topic. 21 | $topic->broadcast(['msg' => $connection->resourceId.' has left '.$topic->getId()]); 22 | } 23 | 24 | /** 25 | * @param mixed $event The event data 26 | */ 27 | public function onPublish( 28 | ConnectionInterface $connection, 29 | Topic $topic, 30 | WampRequest $request, 31 | $event, 32 | array $exclude, 33 | array $eligible 34 | ): void { 35 | /* 36 | $topic->getId() will contain the FULL requested uri, so you can proceed based on that 37 | 38 | if ($topic->getId() == "acme/channel/shout") 39 | //shout something to all subs. 40 | */ 41 | 42 | $topic->broadcast( 43 | [ 44 | 'msg' => $event, 45 | ] 46 | ); 47 | } 48 | 49 | public function getName(): string 50 | { 51 | return 'acme.topic'; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /symfony.lock: -------------------------------------------------------------------------------- 1 | { 2 | "cboden/ratchet": { 3 | "version": "v0.4.3" 4 | }, 5 | "doctrine/annotations": { 6 | "version": "1.0", 7 | "recipe": { 8 | "repo": "github.com/symfony/recipes", 9 | "branch": "master", 10 | "version": "1.0", 11 | "ref": "a2759dd6123694c8d901d0ec80006e044c2e6457" 12 | }, 13 | "files": [ 14 | "config/routes/annotations.yaml" 15 | ] 16 | }, 17 | "doctrine/lexer": { 18 | "version": "1.2.1" 19 | }, 20 | "evenement/evenement": { 21 | "version": "v3.0.1" 22 | }, 23 | "gos/pubsub-router-bundle": { 24 | "version": "v2.5.0" 25 | }, 26 | "gos/web-socket-bundle": { 27 | "version": "v3.7.1" 28 | }, 29 | "gos/websocket-client": { 30 | "version": "v1.3.0" 31 | }, 32 | "guzzlehttp/psr7": { 33 | "version": "1.8.1" 34 | }, 35 | "monolog/monolog": { 36 | "version": "2.2.0" 37 | }, 38 | "php": { 39 | "version": "7.4.12" 40 | }, 41 | "phpdocumentor/reflection-common": { 42 | "version": "2.2.0" 43 | }, 44 | "phpdocumentor/reflection-docblock": { 45 | "version": "5.2.2" 46 | }, 47 | "phpdocumentor/type-resolver": { 48 | "version": "1.4.0" 49 | }, 50 | "psr/cache": { 51 | "version": "2.0.0" 52 | }, 53 | "psr/container": { 54 | "version": "1.1.1" 55 | }, 56 | "psr/event-dispatcher": { 57 | "version": "1.0.0" 58 | }, 59 | "psr/http-message": { 60 | "version": "1.0.1" 61 | }, 62 | "psr/log": { 63 | "version": "1.1.3" 64 | }, 65 | "ralouphie/getallheaders": { 66 | "version": "3.0.3" 67 | }, 68 | "ratchet/rfc6455": { 69 | "version": "v0.3" 70 | }, 71 | "react/cache": { 72 | "version": "v1.1.1" 73 | }, 74 | "react/dns": { 75 | "version": "v1.5.0" 76 | }, 77 | "react/event-loop": { 78 | "version": "v1.1.1" 79 | }, 80 | "react/promise": { 81 | "version": "v2.8.0" 82 | }, 83 | "react/promise-timer": { 84 | "version": "v1.6.0" 85 | }, 86 | "react/socket": { 87 | "version": "v1.6.0" 88 | }, 89 | "react/stream": { 90 | "version": "v1.1.1" 91 | }, 92 | "symfony/apache-pack": { 93 | "version": "1.0", 94 | "recipe": { 95 | "repo": "github.com/symfony/recipes-contrib", 96 | "branch": "master", 97 | "version": "1.0", 98 | "ref": "71599f5b0fdeeeec0fb90e9b17c85e6f5e1350c1" 99 | }, 100 | "files": [ 101 | "public/.htaccess" 102 | ] 103 | }, 104 | "symfony/asset": { 105 | "version": "v5.3.0-beta1" 106 | }, 107 | "symfony/cache": { 108 | "version": "v5.3.0-beta1" 109 | }, 110 | "symfony/cache-contracts": { 111 | "version": "v2.4.0" 112 | }, 113 | "symfony/config": { 114 | "version": "v5.3.0-beta1" 115 | }, 116 | "symfony/console": { 117 | "version": "5.3", 118 | "recipe": { 119 | "repo": "github.com/symfony/recipes", 120 | "branch": "master", 121 | "version": "5.3", 122 | "ref": "da0c8be8157600ad34f10ff0c9cc91232522e047" 123 | }, 124 | "files": [ 125 | "bin/console" 126 | ] 127 | }, 128 | "symfony/debug-bundle": { 129 | "version": "4.1", 130 | "recipe": { 131 | "repo": "github.com/symfony/recipes", 132 | "branch": "master", 133 | "version": "4.1", 134 | "ref": "f8863cbad2f2e58c4b65fa1eac892ab189971bea" 135 | }, 136 | "files": [ 137 | "config/packages/dev/debug.yaml" 138 | ] 139 | }, 140 | "symfony/debug-pack": { 141 | "version": "v1.0.7" 142 | }, 143 | "symfony/dependency-injection": { 144 | "version": "v5.3.0-beta1" 145 | }, 146 | "symfony/deprecation-contracts": { 147 | "version": "v2.4.0" 148 | }, 149 | "symfony/dotenv": { 150 | "version": "v5.3.0-beta1" 151 | }, 152 | "symfony/error-handler": { 153 | "version": "v5.3.0-beta1" 154 | }, 155 | "symfony/event-dispatcher": { 156 | "version": "v5.3.0-beta1" 157 | }, 158 | "symfony/event-dispatcher-contracts": { 159 | "version": "v2.4.0" 160 | }, 161 | "symfony/filesystem": { 162 | "version": "v5.3.0-beta1" 163 | }, 164 | "symfony/finder": { 165 | "version": "v5.3.0-beta1" 166 | }, 167 | "symfony/flex": { 168 | "version": "1.0", 169 | "recipe": { 170 | "repo": "github.com/symfony/recipes", 171 | "branch": "master", 172 | "version": "1.0", 173 | "ref": "c0eeb50665f0f77226616b6038a9b06c03752d8e" 174 | }, 175 | "files": [ 176 | ".env" 177 | ] 178 | }, 179 | "symfony/framework-bundle": { 180 | "version": "5.3", 181 | "recipe": { 182 | "repo": "github.com/symfony/recipes", 183 | "branch": "master", 184 | "version": "5.3", 185 | "ref": "8af7647cd89416f68e41df5c343a5e531d2bf025" 186 | }, 187 | "files": [ 188 | "config/packages/cache.yaml", 189 | "config/packages/framework.yaml", 190 | "config/preload.php", 191 | "config/routes/framework.yaml", 192 | "config/services.yaml", 193 | "public/index.php", 194 | "src/Controller/.gitignore", 195 | "src/Kernel.php" 196 | ] 197 | }, 198 | "symfony/http-client-contracts": { 199 | "version": "v2.4.0" 200 | }, 201 | "symfony/http-foundation": { 202 | "version": "v5.3.0-beta1" 203 | }, 204 | "symfony/http-kernel": { 205 | "version": "v5.3.0-beta1" 206 | }, 207 | "symfony/monolog-bridge": { 208 | "version": "v5.3.0-beta1" 209 | }, 210 | "symfony/monolog-bundle": { 211 | "version": "3.7", 212 | "recipe": { 213 | "repo": "github.com/symfony/recipes", 214 | "branch": "master", 215 | "version": "3.7", 216 | "ref": "329f6a5ef2e7aa033f802be833ef8d1268dd0848" 217 | }, 218 | "files": [ 219 | "config/packages/dev/monolog.yaml", 220 | "config/packages/prod/deprecations.yaml", 221 | "config/packages/prod/monolog.yaml", 222 | "config/packages/test/monolog.yaml" 223 | ] 224 | }, 225 | "symfony/options-resolver": { 226 | "version": "v5.3.0-beta1" 227 | }, 228 | "symfony/password-hasher": { 229 | "version": "v5.3.0-beta1" 230 | }, 231 | "symfony/polyfill-intl-grapheme": { 232 | "version": "v1.22.1" 233 | }, 234 | "symfony/polyfill-intl-normalizer": { 235 | "version": "v1.22.1" 236 | }, 237 | "symfony/polyfill-mbstring": { 238 | "version": "v1.22.1" 239 | }, 240 | "symfony/polyfill-php80": { 241 | "version": "v1.22.1" 242 | }, 243 | "symfony/process": { 244 | "version": "v4.3.1" 245 | }, 246 | "symfony/profiler-pack": { 247 | "version": "v1.0.4" 248 | }, 249 | "symfony/property-access": { 250 | "version": "v5.3.0-beta1" 251 | }, 252 | "symfony/property-info": { 253 | "version": "v5.3.0-beta1" 254 | }, 255 | "symfony/routing": { 256 | "version": "5.1", 257 | "recipe": { 258 | "repo": "github.com/symfony/recipes", 259 | "branch": "master", 260 | "version": "5.1", 261 | "ref": "b4f3e7c95e38b606eef467e8a42a8408fc460c43" 262 | }, 263 | "files": [ 264 | "config/packages/prod/routing.yaml", 265 | "config/packages/routing.yaml", 266 | "config/routes.yaml" 267 | ] 268 | }, 269 | "symfony/runtime": { 270 | "version": "v5.3.0-beta1" 271 | }, 272 | "symfony/security-bundle": { 273 | "version": "5.1", 274 | "recipe": { 275 | "repo": "github.com/symfony/recipes", 276 | "branch": "master", 277 | "version": "5.1", 278 | "ref": "0a4bae19389d3b9cba1ca0102e3b2bccea724603" 279 | }, 280 | "files": [ 281 | "config/packages/security.yaml" 282 | ] 283 | }, 284 | "symfony/security-core": { 285 | "version": "v5.3.0-beta1" 286 | }, 287 | "symfony/security-csrf": { 288 | "version": "v5.3.0-beta1" 289 | }, 290 | "symfony/security-guard": { 291 | "version": "v5.3.0-beta1" 292 | }, 293 | "symfony/security-http": { 294 | "version": "v5.3.0-beta1" 295 | }, 296 | "symfony/serializer": { 297 | "version": "v5.3.0-beta1" 298 | }, 299 | "symfony/serializer-pack": { 300 | "version": "v1.0.2" 301 | }, 302 | "symfony/service-contracts": { 303 | "version": "v2.4.0" 304 | }, 305 | "symfony/stopwatch": { 306 | "version": "v5.3.0-beta1" 307 | }, 308 | "symfony/string": { 309 | "version": "v5.3.0-beta1" 310 | }, 311 | "symfony/translation-contracts": { 312 | "version": "v2.4.0" 313 | }, 314 | "symfony/twig-bridge": { 315 | "version": "v5.3.0-beta1" 316 | }, 317 | "symfony/twig-bundle": { 318 | "version": "5.0", 319 | "recipe": { 320 | "repo": "github.com/symfony/recipes", 321 | "branch": "master", 322 | "version": "5.0", 323 | "ref": "fab9149bbaa4d5eca054ed93f9e1b66cc500895d" 324 | }, 325 | "files": [ 326 | "config/packages/test/twig.yaml", 327 | "config/packages/twig.yaml", 328 | "templates/base.html.twig" 329 | ] 330 | }, 331 | "symfony/var-dumper": { 332 | "version": "v5.3.0-beta1" 333 | }, 334 | "symfony/var-exporter": { 335 | "version": "v5.3.0-beta1" 336 | }, 337 | "symfony/web-profiler-bundle": { 338 | "version": "3.3", 339 | "recipe": { 340 | "repo": "github.com/symfony/recipes", 341 | "branch": "master", 342 | "version": "3.3", 343 | "ref": "6bdfa1a95f6b2e677ab985cd1af2eae35d62e0f6" 344 | }, 345 | "files": [ 346 | "config/packages/dev/web_profiler.yaml", 347 | "config/packages/test/web_profiler.yaml", 348 | "config/routes/dev/web_profiler.yaml" 349 | ] 350 | }, 351 | "symfony/web-server-bundle": { 352 | "version": "3.3", 353 | "recipe": { 354 | "repo": "github.com/symfony/recipes", 355 | "branch": "master", 356 | "version": "3.3", 357 | "ref": "dae9b39fd6717970be7601101ce5aa960bf53d9a" 358 | } 359 | }, 360 | "symfony/yaml": { 361 | "version": "v5.3.0-beta1" 362 | }, 363 | "twig/twig": { 364 | "version": "v3.3.0" 365 | }, 366 | "webmozart/assert": { 367 | "version": "1.10.0" 368 | }, 369 | "zendframework/zend-code": { 370 | "version": "3.3.1" 371 | }, 372 | "zendframework/zend-eventmanager": { 373 | "version": "3.2.1" 374 | } 375 | } 376 | -------------------------------------------------------------------------------- /templates/base.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}Welcome!{% endblock %} 6 | {% block stylesheets %}{% endblock %} 7 | 8 | 9 | {% block body %}{% endblock %} 10 | {% block javascripts %}{% endblock %} 11 | 12 | 13 | -------------------------------------------------------------------------------- /templates/homepage.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | {% block body %} 4 | Homepage. 5 | {% endblock %} 6 | 7 | {% block javascripts %} 8 | 9 | 10 | 11 | 48 | {% endblock %} 49 | -------------------------------------------------------------------------------- /var/cache/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeniusesOfSymfony/WebsocketAppDemo/e99570a9afba7f82fa2e76c3b1730792b7570115/var/cache/.gitkeep --------------------------------------------------------------------------------