├── .gitignore ├── .idea └── typescript-compiler.xml ├── LICENSE ├── README.md ├── app ├── .htaccess ├── AppCache.php ├── AppKernel.php ├── Resources │ └── views │ │ ├── base.html.twig │ │ └── default │ │ └── index.html.twig ├── autoload.php ├── config │ ├── config.yml │ ├── config_dev.yml │ ├── config_prod.yml │ ├── config_test.yml │ ├── parameters.yml.dist │ ├── routing.yml │ ├── routing_dev.yml │ ├── security.yml │ └── services.yml └── data.db3 ├── bin ├── console └── symfony_requirements ├── composer.json ├── composer.lock ├── phpunit.xml.dist ├── src ├── .htaccess └── AppBundle │ ├── AppBundle.php │ ├── Controller │ └── DefaultController.php │ ├── Entity │ └── Apartment.php │ ├── Repository │ └── ApartmentRepository.php │ ├── Resources │ └── public │ │ ├── css │ │ ├── app.css │ │ └── milligram.min.css │ │ └── js │ │ ├── axios.min.js │ │ ├── react │ │ ├── app.js │ │ └── dist │ │ │ ├── app.2432197f.js │ │ │ ├── app.2432197f.js.map │ │ │ ├── index.html │ │ │ ├── manifest.d41d8cd9.js │ │ │ └── manifest.d41d8cd9.js.map │ │ ├── typescript │ │ ├── app.ts │ │ ├── appstate.d.ts │ │ ├── axios.d.ts │ │ ├── dist │ │ │ └── app.js │ │ └── tsconfig.json │ │ └── vue │ │ ├── app.js │ │ ├── tsconfig.json │ │ └── vue.js │ └── State │ └── AppState.php ├── tests └── AppBundle │ └── Controller │ └── DefaultControllerTest.php ├── var ├── SymfonyRequirements.php ├── cache │ └── .gitkeep ├── logs │ └── .gitkeep └── sessions │ └── .gitkeep └── web ├── .htaccess ├── app.php ├── app_dev.php ├── apple-touch-icon.png ├── config.php ├── favicon.ico └── robots.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /app/config/parameters.yml 3 | /build/ 4 | /phpunit.xml 5 | /var/* 6 | !/var/cache 7 | /var/cache/* 8 | !var/cache/.gitkeep 9 | !/var/logs 10 | /var/logs/* 11 | !var/logs/.gitkeep 12 | !/var/sessions 13 | /var/sessions/* 14 | !var/sessions/.gitkeep 15 | !var/SymfonyRequirements.php 16 | /vendor/ 17 | /web/bundles/ 18 | -------------------------------------------------------------------------------- /.idea/typescript-compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License 3 | 4 | Copyright (c) 2017 Jani Tarvainen, http://janit.iki.fi/ 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A Symfony hybrid app sharing state object with Twig, React and Vue 2 | ========== 3 | 4 | A Symfony project created on January 14, 2017, 9:23 am. 5 | 6 | An effort to provide a working example concept of simply 7 | sharing a state object between the Twig template rendering engine 8 | as well as JavaScript view layers Vue and React. 9 | 10 | This introduces no complexity of server side rendering for decent 11 | performance, but SSR can be done as an enhancement for improved 12 | performance and SEO: Introduction to React.js Components and Server Side Rendering in PHP, Testing React.js isomorphic rendering with php-v8js and the Symfony Microkernel 13 | 14 | This will just handle the sharing of initial state on page load 15 | and you'll need to then take over your state management in your 16 | front end using some kind of tools for that, e.g. MobX, Redux. 17 | There is also a simple API backend that also returns the same 18 | object and keeps things predictable for developers. 19 | 20 | The application comes complete with an SQLite database and built 21 | JavaScript clients to keep overhead of installation minimal. The 22 | application itself is simple enough to figure out with basic 23 | understanding of OO PHP and Symfony, so it's better just to take 24 | a look for yourself to see if this feels like a good idea or not. 25 | 26 | ## Installation 27 | 28 | Clone app: 29 | 30 | ``` 31 | git clone git@github.com:janit/symfony-hybrid-twig-react-vue.git 32 | ``` 33 | 34 | Install dependencies: 35 | 36 | ``` 37 | composer install 38 | ``` 39 | 40 | Run: 41 | 42 | ``` 43 | ./bin/console server:run 44 | ``` 45 | 46 | Open app in browser: http://localhost:8000 47 | 48 | ## JavaScript builds 49 | 50 | There are three separate client implementations included, React, Vue.js and Vanilla JavaScript (via TypeScript). If you want to try modifications to the behaviour of the clients you'll need to do some build setup: 51 | 52 | ### Vue.js 53 | 54 | No Vue there is build process, just start editing `src/AppBundle/Resources/public/js/vue/app.js`. Note that example uses some the ES6+ syntax is not supported natively everywhere, so you'll need an up-to-date browser. 55 | 56 | ### React 57 | 58 | The React app is built using nwb, a fast way to get started with contemporary (as of February 2017) JavaScript builds. 59 | 60 | Install nwb globally: 61 | 62 | ``` 63 | npm install -g nwb 64 | ``` 65 | 66 | Enter directory and run build: 67 | 68 | ``` 69 | cd src/AppBundle/Resources/public/js/react 70 | react build app.js 71 | ``` 72 | 73 | The built filename changes by default, so unless you tweak config, you'll need to edit `app/Resources/views/base.html.twig` to the current one. 74 | 75 | ### JavaScript / TypeScript 76 | 77 | The vanilla JavaScript app is written in TypeScript, which adds type information and some other syntax on top of the JavaScript language. 78 | 79 | The easiest way to work with TypeScript is use an editor which supports the language (such as PhpStorm, Visual Studio Code, etc...) out of the box, but otherwise you can also install the TypeScript compiler and do compilation manually: 80 | 81 | ``` 82 | npm i -g typescript 83 | src/AppBundle/Resources/public/js/typescript/ 84 | tsc app.ts 85 | ``` 86 | 87 | The vanilla JavaScript app is written in TypeScript, which adds type information and some other syntax on top of the JavaScript language. 88 | The vanilla JavaScript app is written in TypeScript, which adds type information and some other syntax on top of the JavaScript language. 89 | ## Background information to follow 90 | 91 | As a bonus I will be adding example TypeScript Type Definitions 92 | for the example animation of how it is like to work with TypeScript 93 | and how you could benefit from using strong types in your front 94 | end development workflow. 95 | 96 | An article with the background is published here: Sharing state in a Symfony hybrid with Twig, React and other JavaScript apps 97 | -------------------------------------------------------------------------------- /app/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Order deny,allow 6 | Deny from all 7 | 8 | -------------------------------------------------------------------------------- /app/AppCache.php: -------------------------------------------------------------------------------- 1 | getEnvironment(), ['dev', 'test'], true)) { 23 | $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle(); 24 | $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); 25 | $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); 26 | $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); 27 | $bundles[] = new Symfony\Bundle\WebServerBundle\WebServerBundle(); 28 | } 29 | 30 | return $bundles; 31 | } 32 | 33 | public function getRootDir() 34 | { 35 | return __DIR__; 36 | } 37 | 38 | public function getCacheDir() 39 | { 40 | return dirname(__DIR__).'/var/cache/'.$this->getEnvironment(); 41 | } 42 | 43 | public function getLogDir() 44 | { 45 | return dirname(__DIR__).'/var/logs'; 46 | } 47 | 48 | public function registerContainerConfiguration(LoaderInterface $loader) 49 | { 50 | $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml'); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/Resources/views/base.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% block title %}Apartments demo{% endblock %} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

17 | Home 18 | List 10 19 | List 100 20 | List 300 21 | List apartments in Finland 22 | List apartments in Japan 23 |

24 | 25 |
26 | 27 | {% block body %} 28 | {% endblock %} 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /app/Resources/views/default/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | {% block body %} 4 | 5 |
6 | 7 |
8 |
9 |

Hello from Twig

10 | 11 | {% for apartment in appstate.apartments %} 12 | 13 | 18 | 19 | 20 | 21 | {% endfor %} 22 |
14 | {{ apartment.streetaddress }}
15 | {{ apartment.city }}
16 | {{ apartment.zipcode }} 17 |
{{ apartment.country }}{{ apartment.buildyear }}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | 33 | {% endblock %} -------------------------------------------------------------------------------- /app/autoload.php: -------------------------------------------------------------------------------- 1 | getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev'); 20 | $debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod'; 21 | 22 | if ($debug) { 23 | Debug::enable(); 24 | } 25 | 26 | $kernel = new AppKernel($env, $debug); 27 | $application = new Application($kernel); 28 | $application->run($input); 29 | -------------------------------------------------------------------------------- /bin/symfony_requirements: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | getPhpIniConfigPath(); 9 | 10 | echo_title('Symfony Requirements Checker'); 11 | 12 | echo '> PHP is using the following php.ini file:'.PHP_EOL; 13 | if ($iniPath) { 14 | echo_style('green', ' '.$iniPath); 15 | } else { 16 | echo_style('yellow', ' WARNING: No configuration file (php.ini) used by PHP!'); 17 | } 18 | 19 | echo PHP_EOL.PHP_EOL; 20 | 21 | echo '> Checking Symfony requirements:'.PHP_EOL.' '; 22 | 23 | $messages = array(); 24 | foreach ($symfonyRequirements->getRequirements() as $req) { 25 | if ($helpText = get_error_message($req, $lineSize)) { 26 | echo_style('red', 'E'); 27 | $messages['error'][] = $helpText; 28 | } else { 29 | echo_style('green', '.'); 30 | } 31 | } 32 | 33 | $checkPassed = empty($messages['error']); 34 | 35 | foreach ($symfonyRequirements->getRecommendations() as $req) { 36 | if ($helpText = get_error_message($req, $lineSize)) { 37 | echo_style('yellow', 'W'); 38 | $messages['warning'][] = $helpText; 39 | } else { 40 | echo_style('green', '.'); 41 | } 42 | } 43 | 44 | if ($checkPassed) { 45 | echo_block('success', 'OK', 'Your system is ready to run Symfony projects'); 46 | } else { 47 | echo_block('error', 'ERROR', 'Your system is not ready to run Symfony projects'); 48 | 49 | echo_title('Fix the following mandatory requirements', 'red'); 50 | 51 | foreach ($messages['error'] as $helpText) { 52 | echo ' * '.$helpText.PHP_EOL; 53 | } 54 | } 55 | 56 | if (!empty($messages['warning'])) { 57 | echo_title('Optional recommendations to improve your setup', 'yellow'); 58 | 59 | foreach ($messages['warning'] as $helpText) { 60 | echo ' * '.$helpText.PHP_EOL; 61 | } 62 | } 63 | 64 | echo PHP_EOL; 65 | echo_style('title', 'Note'); 66 | echo ' The command console could use a different php.ini file'.PHP_EOL; 67 | echo_style('title', '~~~~'); 68 | echo ' than the one used with your web server. To be on the'.PHP_EOL; 69 | echo ' safe side, please check the requirements from your web'.PHP_EOL; 70 | echo ' server using the '; 71 | echo_style('yellow', 'web/config.php'); 72 | echo ' script.'.PHP_EOL; 73 | echo PHP_EOL; 74 | 75 | exit($checkPassed ? 0 : 1); 76 | 77 | function get_error_message(Requirement $requirement, $lineSize) 78 | { 79 | if ($requirement->isFulfilled()) { 80 | return; 81 | } 82 | 83 | $errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL.' ').PHP_EOL; 84 | $errorMessage .= ' > '.wordwrap($requirement->getHelpText(), $lineSize - 5, PHP_EOL.' > ').PHP_EOL; 85 | 86 | return $errorMessage; 87 | } 88 | 89 | function echo_title($title, $style = null) 90 | { 91 | $style = $style ?: 'title'; 92 | 93 | echo PHP_EOL; 94 | echo_style($style, $title.PHP_EOL); 95 | echo_style($style, str_repeat('~', strlen($title)).PHP_EOL); 96 | echo PHP_EOL; 97 | } 98 | 99 | function echo_style($style, $message) 100 | { 101 | // ANSI color codes 102 | $styles = array( 103 | 'reset' => "\033[0m", 104 | 'red' => "\033[31m", 105 | 'green' => "\033[32m", 106 | 'yellow' => "\033[33m", 107 | 'error' => "\033[37;41m", 108 | 'success' => "\033[37;42m", 109 | 'title' => "\033[34m", 110 | ); 111 | $supports = has_color_support(); 112 | 113 | echo($supports ? $styles[$style] : '').$message.($supports ? $styles['reset'] : ''); 114 | } 115 | 116 | function echo_block($style, $title, $message) 117 | { 118 | $message = ' '.trim($message).' '; 119 | $width = strlen($message); 120 | 121 | echo PHP_EOL.PHP_EOL; 122 | 123 | echo_style($style, str_repeat(' ', $width)); 124 | echo PHP_EOL; 125 | echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT)); 126 | echo PHP_EOL; 127 | echo_style($style, $message); 128 | echo PHP_EOL; 129 | echo_style($style, str_repeat(' ', $width)); 130 | echo PHP_EOL; 131 | } 132 | 133 | function has_color_support() 134 | { 135 | static $support; 136 | 137 | if (null === $support) { 138 | if (DIRECTORY_SEPARATOR == '\\') { 139 | $support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI'); 140 | } else { 141 | $support = function_exists('posix_isatty') && @posix_isatty(STDOUT); 142 | } 143 | } 144 | 145 | return $support; 146 | } 147 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "janit/state-demo", 3 | "license": "proprietary", 4 | "type": "project", 5 | "autoload": { 6 | "psr-4": { 7 | "": "src/" 8 | }, 9 | "classmap": [ 10 | "app/AppKernel.php", 11 | "app/AppCache.php" 12 | ] 13 | }, 14 | "autoload-dev": { 15 | "psr-4": { 16 | "Tests\\": "tests/" 17 | } 18 | }, 19 | "require": { 20 | "php": ">=5.5.9", 21 | "symfony/symfony": "3.3.*", 22 | "doctrine/orm": "^2.5", 23 | "doctrine/doctrine-bundle": "^1.6", 24 | "doctrine/doctrine-cache-bundle": "^1.2", 25 | "symfony/swiftmailer-bundle": "^2.3", 26 | "symfony/monolog-bundle": "^3.0", 27 | "symfony/polyfill-apcu": "^1.0", 28 | "sensio/distribution-bundle": "^5.0", 29 | "sensio/framework-extra-bundle": "^3.0.2", 30 | "incenteev/composer-parameter-handler": "^2.0", 31 | "javiereguiluz/easyadmin-bundle": "^1.16", 32 | "fzaninotto/faker": "^1.6" 33 | }, 34 | "require-dev": { 35 | "sensio/generator-bundle": "^3.0", 36 | "symfony/phpunit-bridge": "^3.0", 37 | "symfony/web-server-bundle": "^3.3" 38 | }, 39 | "scripts": { 40 | "symfony-scripts": [ 41 | "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", 42 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", 43 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", 44 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", 45 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", 46 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget" 47 | ], 48 | "post-install-cmd": [ 49 | "@symfony-scripts" 50 | ], 51 | "post-update-cmd": [ 52 | "@symfony-scripts" 53 | ] 54 | }, 55 | "extra": { 56 | "symfony-app-dir": "app", 57 | "symfony-bin-dir": "bin", 58 | "symfony-var-dir": "var", 59 | "symfony-web-dir": "web", 60 | "symfony-tests-dir": "tests", 61 | "symfony-assets-install": "relative", 62 | "incenteev-parameters": { 63 | "file": "app/config/parameters.yml" 64 | }, 65 | "branch-alias": null 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | tests 18 | 19 | 20 | 21 | 22 | 23 | src 24 | 25 | src/*Bundle/Resources 26 | src/*/*Bundle/Resources 27 | src/*/Bundle/*Bundle/Resources 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Order deny,allow 6 | Deny from all 7 | 8 | -------------------------------------------------------------------------------- /src/AppBundle/AppBundle.php: -------------------------------------------------------------------------------- 1 | get('doctrine.orm.default_entity_manager'); 24 | $apartments = $em->getRepository('AppBundle:Apartment')->findByLimit(3); 25 | 26 | $appState->setApartments($apartments); 27 | $appState->setFetchMore(true); 28 | 29 | return $this->render('default/index.html.twig', [ 30 | 'appstate' => $appState, 31 | 'appstate_serialized' => $appState->jsonSerialize() 32 | ]); 33 | } 34 | 35 | 36 | /** 37 | * @Route("/limit/{limit}", name="limited") 38 | */ 39 | public function limitedAction(Request $request, int $limit = 3 ) 40 | { 41 | 42 | $appState = new AppState(); 43 | 44 | $em = $this->get('doctrine.orm.default_entity_manager'); 45 | $apartments = $em->getRepository('AppBundle:Apartment')->findByLimit($limit); 46 | 47 | $appState->setApartments($apartments); 48 | 49 | return $this->render('default/index.html.twig', [ 50 | 'appstate' => $appState, 51 | 'appstate_serialized' => $appState->jsonSerialize() 52 | ]); 53 | } 54 | 55 | /** 56 | * @Route("/country/{country}", name="filtered") 57 | */ 58 | public function filteredAction(Request $request, $country=false ) 59 | { 60 | 61 | $appState = new AppState(); 62 | 63 | $em = $this->get('doctrine.orm.default_entity_manager'); 64 | $apartments = $em->getRepository('AppBundle:Apartment')->findByCountry($country); 65 | 66 | $appState->setSelectedCountry($country); 67 | $appState->setSortBy($country); 68 | $appState->setApartments($apartments); 69 | 70 | return $this->render('default/index.html.twig', [ 71 | 'appstate' => $appState, 72 | 'appstate_serialized' => $appState->jsonSerialize() 73 | ]); 74 | } 75 | 76 | 77 | /** 78 | * @Route("/api", name="api") 79 | */ 80 | public function apiApartmentsAction(Request $request) 81 | { 82 | 83 | $appState = new AppState(); 84 | 85 | $cache = new FilesystemCache(); 86 | $cacheKey = 'apartments'; 87 | 88 | if (!$cache->has($cacheKey)) { 89 | 90 | $em = $this->get('doctrine.orm.default_entity_manager'); 91 | $apartments = $em->getRepository('App:Apartment')->findByLimit(10); 92 | 93 | $cache->set($cacheKey, $apartments, 3600); 94 | } 95 | 96 | $apartments = $cache->get($cacheKey); 97 | 98 | $appState->setApartments($apartments); 99 | 100 | $response = new JsonResponse(); 101 | 102 | $response->setContent($appState->jsonSerialize()); 103 | 104 | return $response; 105 | 106 | } 107 | 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/AppBundle/Entity/Apartment.php: -------------------------------------------------------------------------------- 1 | id; 75 | } 76 | 77 | /** 78 | * Set streetaddress 79 | * 80 | * @param string $streetaddress 81 | * 82 | * @return Apartment 83 | */ 84 | public function setStreetaddress($streetaddress) 85 | { 86 | $this->streetaddress = $streetaddress; 87 | 88 | return $this; 89 | } 90 | 91 | /** 92 | * Get streetaddress 93 | * 94 | * @return string 95 | */ 96 | public function getStreetaddress() 97 | { 98 | return $this->streetaddress; 99 | } 100 | 101 | /** 102 | * Set city 103 | * 104 | * @param string $city 105 | * 106 | * @return Apartment 107 | */ 108 | public function setCity($city) 109 | { 110 | $this->city = $city; 111 | 112 | return $this; 113 | } 114 | 115 | /** 116 | * Get city 117 | * 118 | * @return string 119 | */ 120 | public function getCity() 121 | { 122 | return $this->city; 123 | } 124 | 125 | /** 126 | * Set zipcode 127 | * 128 | * @param string $zipcode 129 | * 130 | * @return Apartment 131 | */ 132 | public function setZipcode($zipcode) 133 | { 134 | $this->zipcode = $zipcode; 135 | 136 | return $this; 137 | } 138 | 139 | /** 140 | * Get zipcode 141 | * 142 | * @return string 143 | */ 144 | public function getZipcode() 145 | { 146 | return $this->zipcode; 147 | } 148 | 149 | /** 150 | * Set country 151 | * 152 | * @param string $country 153 | * 154 | * @return Apartment 155 | */ 156 | public function setCountry($country) 157 | { 158 | $this->country = $country; 159 | 160 | return $this; 161 | } 162 | 163 | /** 164 | * Get country 165 | * 166 | * @return string 167 | */ 168 | public function getCountry() 169 | { 170 | return $this->country; 171 | } 172 | 173 | /** 174 | * Set buildyear 175 | * 176 | * @param integer $buildyear 177 | * 178 | * @return Apartment 179 | */ 180 | public function setBuildyear($buildyear) 181 | { 182 | $this->buildyear = $buildyear; 183 | 184 | return $this; 185 | } 186 | 187 | /** 188 | * Get buildyear 189 | * 190 | * @return int 191 | */ 192 | public function getBuildyear() 193 | { 194 | return $this->buildyear; 195 | } 196 | 197 | /** 198 | * Set size 199 | * 200 | * @param integer $size 201 | * 202 | * @return Apartment 203 | */ 204 | public function setSize($size) 205 | { 206 | $this->size = $size; 207 | 208 | return $this; 209 | } 210 | 211 | /** 212 | * Get size 213 | * 214 | * @return int 215 | */ 216 | public function getSize() 217 | { 218 | return $this->size; 219 | } 220 | } 221 | 222 | -------------------------------------------------------------------------------- /src/AppBundle/Repository/ApartmentRepository.php: -------------------------------------------------------------------------------- 1 | getEntityManager() 16 | ->createQuery( 17 | 'SELECT a 18 | FROM AppBundle:Apartment a 19 | ORDER BY a.id ASC' 20 | )->setMaxResults($limit); 21 | 22 | try { 23 | return $query->getResult(); 24 | } catch (\Doctrine\ORM\NoResultException $e) { 25 | return null; 26 | } 27 | } 28 | 29 | public function getRandom($limit) 30 | { 31 | $query = $this->getEntityManager() 32 | ->createQuery( 33 | 'SELECT a 34 | FROM AppBundle:Apartment a' 35 | ); 36 | 37 | try { 38 | 39 | // dirty, but I don't give a fuck #thuglife 40 | $results = $query->getResult(); 41 | shuffle($results); 42 | return array_slice($results,0,$limit); 43 | 44 | } catch (\Doctrine\ORM\NoResultException $e) { 45 | return null; 46 | } 47 | } 48 | 49 | public function finByCountry($country) 50 | { 51 | $query = $this->getEntityManager() 52 | ->createQuery( 53 | 'SELECT a 54 | FROM AppBundle:Apartment a 55 | WHERE a.country = :selectedCountry 56 | ORDER BY a.buildyear ASC' 57 | )->setParameter('selectedCountry',$country); 58 | 59 | try { 60 | return $query->getResult(); 61 | } catch (\Doctrine\ORM\NoResultException $e) { 62 | return null; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/css/app.css: -------------------------------------------------------------------------------- 1 | 2 | .column-twig { 3 | padding: 3em; 4 | } 5 | 6 | .column-twig { 7 | background-color: #f0f0f0; 8 | } 9 | 10 | .column-vue { 11 | background: #c4e3f3; 12 | } 13 | 14 | .column-react { 15 | background-color: #F5DEB3; 16 | } -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/css/milligram.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Milligram v1.1.0 3 | * http://milligram.github.io 4 | * 5 | * Copyright (c) 2016 CJ Patoilo 6 | * Licensed under the MIT license 7 | */ 8 | 9 | 10 | html{box-sizing:border-box;font-size:62.5%}body{color:#606c76;font-family:"Arial",sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}*,*:after,*:before{box-sizing:inherit}blockquote{border-left:.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin:0}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:#9b4dca;border:.1rem solid #9b4dca;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:hover,.button:focus,button:hover,button:focus,input[type='button']:hover,input[type='button']:focus,input[type='reset']:hover,input[type='reset']:focus,input[type='submit']:hover,input[type='submit']:focus{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button.button-disabled,.button[disabled],button.button-disabled,button[disabled],input[type='button'].button-disabled,input[type='button'][disabled],input[type='reset'].button-disabled,input[type='reset'][disabled],input[type='submit'].button-disabled,input[type='submit'][disabled]{opacity:.5;cursor:default}.button.button-disabled:hover,.button.button-disabled:focus,.button[disabled]:hover,.button[disabled]:focus,button.button-disabled:hover,button.button-disabled:focus,button[disabled]:hover,button[disabled]:focus,input[type='button'].button-disabled:hover,input[type='button'].button-disabled:focus,input[type='button'][disabled]:hover,input[type='button'][disabled]:focus,input[type='reset'].button-disabled:hover,input[type='reset'].button-disabled:focus,input[type='reset'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='submit'].button-disabled:hover,input[type='submit'].button-disabled:focus,input[type='submit'][disabled]:hover,input[type='submit'][disabled]:focus{background-color:#9b4dca;border-color:#9b4dca}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{color:#9b4dca;background-color:transparent}.button.button-outline:hover,.button.button-outline:focus,button.button-outline:hover,button.button-outline:focus,input[type='button'].button-outline:hover,input[type='button'].button-outline:focus,input[type='reset'].button-outline:hover,input[type='reset'].button-outline:focus,input[type='submit'].button-outline:hover,input[type='submit'].button-outline:focus{color:#606c76;background-color:transparent;border-color:#606c76}.button.button-outline.button-disabled:hover,.button.button-outline.button-disabled:focus,.button.button-outline[disabled]:hover,.button.button-outline[disabled]:focus,button.button-outline.button-disabled:hover,button.button-outline.button-disabled:focus,button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,input[type='button'].button-outline.button-disabled:hover,input[type='button'].button-outline.button-disabled:focus,input[type='button'].button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='reset'].button-outline.button-disabled:hover,input[type='reset'].button-outline.button-disabled:focus,input[type='reset'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='submit'].button-outline.button-disabled:hover,input[type='submit'].button-outline.button-disabled:focus,input[type='submit'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus{color:#9b4dca;border-color:inherit}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{color:#9b4dca;background-color:transparent;border-color:transparent}.button.button-clear:hover,.button.button-clear:focus,button.button-clear:hover,button.button-clear:focus,input[type='button'].button-clear:hover,input[type='button'].button-clear:focus,input[type='reset'].button-clear:hover,input[type='reset'].button-clear:focus,input[type='submit'].button-clear:hover,input[type='submit'].button-clear:focus{color:#606c76;background-color:transparent;border-color:transparent}.button.button-clear.button-disabled:hover,.button.button-clear.button-disabled:focus,.button.button-clear[disabled]:hover,.button.button-clear[disabled]:focus,button.button-clear.button-disabled:hover,button.button-clear.button-disabled:focus,button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,input[type='button'].button-clear.button-disabled:hover,input[type='button'].button-clear.button-disabled:focus,input[type='button'].button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='reset'].button-clear.button-disabled:hover,input[type='reset'].button-clear.button-disabled:focus,input[type='reset'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='submit'].button-clear.button-disabled:hover,input[type='submit'].button-clear.button-disabled:focus,input[type='submit'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus{color:#9b4dca}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;padding:.2rem .5rem;margin:0 .2rem;white-space:nowrap}pre{background:#f4f5f6;border-left:.3rem solid #9b4dca;font-family:"Menlo","Consolas","Bitstream Vera Sans Mono","DejaVu Sans Mono","Monaco",monospace}pre>code{background:transparent;border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:.1rem solid #f4f5f6;margin-bottom:3.5rem;margin-top:3rem}input[type='email'],input[type='number'],input[type='password'],input[type='search'],input[type='tel'],input[type='text'],input[type='url'],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:none;height:3.8rem;padding:.6rem 1rem;width:100%}input[type='email']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,textarea:focus,select:focus{border:.1rem solid #9b4dca;outline:0}select{padding:.6rem 3rem .6rem 1rem;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMjkgMTQiICAgaGVpZ2h0PSIxNHB4IiAgIGlkPSJMYXllcl8xIiAgIHZlcnNpb249IjEuMSIgICB2aWV3Qm94PSIwIDAgMjkgMTQiICAgd2lkdGg9IjI5cHgiICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjQgcjk5MzkiICAgc29kaXBvZGk6ZG9jbmFtZT0iY2FyZXQtZ3JheS5zdmciPjxtZXRhZGF0YSAgICAgaWQ9Im1ldGFkYXRhMzAzOSI+PHJkZjpSREY+PGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+PGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+PGRjOnR5cGUgICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+PC9jYzpXb3JrPjwvcmRmOlJERj48L21ldGFkYXRhPjxkZWZzICAgICBpZD0iZGVmczMwMzciIC8+PHNvZGlwb2RpOm5hbWVkdmlldyAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiICAgICBib3JkZXJvcGFjaXR5PSIxIiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIgICAgIGdyaWR0b2xlcmFuY2U9IjEwIiAgICAgZ3VpZGV0b2xlcmFuY2U9IjEwIiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSI5MDMiICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI1OTQiICAgICBpZD0ibmFtZWR2aWV3MzAzNSIgICAgIHNob3dncmlkPSJ0cnVlIiAgICAgaW5rc2NhcGU6em9vbT0iMTIuMTM3OTMxIiAgICAgaW5rc2NhcGU6Y3g9Ii00LjExOTMxODJlLTA4IiAgICAgaW5rc2NhcGU6Y3k9IjciICAgICBpbmtzY2FwZTp3aW5kb3cteD0iNTAyIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjMwMiIgICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJMYXllcl8xIj48aW5rc2NhcGU6Z3JpZCAgICAgICB0eXBlPSJ4eWdyaWQiICAgICAgIGlkPSJncmlkMzA0MSIgLz48L3NvZGlwb2RpOm5hbWVkdmlldz48cG9seWdvbiAgICAgcG9pbnRzPSIwLjE1LDAgMTQuNSwxNC4zNSAyOC44NSwwICIgICAgIGlkPSJwb2x5Z29uMzAzMyIgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzU0MTEzODcsMCwwLDAuNDgzMjkxMSw5LjMyNDE1NDUsMy42MjQ5OTkyKSIgICAgIHN0eWxlPSJmaWxsOiNkMWQxZDE7ZmlsbC1vcGFjaXR5OjEiIC8+PC9zdmc+) center right no-repeat}select:focus{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMjkgMTQiICAgaGVpZ2h0PSIxNHB4IiAgIGlkPSJMYXllcl8xIiAgIHZlcnNpb249IjEuMSIgICB2aWV3Qm94PSIwIDAgMjkgMTQiICAgd2lkdGg9IjI5cHgiICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjQgcjk5MzkiICAgc29kaXBvZGk6ZG9jbmFtZT0iY2FyZXQuc3ZnIj48bWV0YWRhdGEgICAgIGlkPSJtZXRhZGF0YTMwMzkiPjxyZGY6UkRGPjxjYzpXb3JrICAgICAgICAgcmRmOmFib3V0PSIiPjxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PjxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPjwvY2M6V29yaz48L3JkZjpSREY+PC9tZXRhZGF0YT48ZGVmcyAgICAgaWQ9ImRlZnMzMDM3IiAvPjxzb2RpcG9kaTpuYW1lZHZpZXcgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMSIgICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiICAgICBncmlkdG9sZXJhbmNlPSIxMCIgICAgIGd1aWRldG9sZXJhbmNlPSIxMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iOTAzIiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iNTk0IiAgICAgaWQ9Im5hbWVkdmlldzMwMzUiICAgICBzaG93Z3JpZD0idHJ1ZSIgICAgIGlua3NjYXBlOnpvb209IjEyLjEzNzkzMSIgICAgIGlua3NjYXBlOmN4PSItNC4xMTkzMTgyZS0wOCIgICAgIGlua3NjYXBlOmN5PSI3IiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjUwMiIgICAgIGlua3NjYXBlOndpbmRvdy15PSIzMDIiICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIwIiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iTGF5ZXJfMSI+PGlua3NjYXBlOmdyaWQgICAgICAgdHlwZT0ieHlncmlkIiAgICAgICBpZD0iZ3JpZDMwNDEiIC8+PC9zb2RpcG9kaTpuYW1lZHZpZXc+PHBvbHlnb24gICAgIHBvaW50cz0iMjguODUsMCAwLjE1LDAgMTQuNSwxNC4zNSAiICAgICBpZD0icG9seWdvbjMwMzMiICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1NDExMzg3LDAsMCwwLjQ4MzI5MTEsOS4zMjQxNTUzLDMuNjI1KSIgICAgIHN0eWxlPSJmaWxsOiM5YjRkY2Y7ZmlsbC1vcGFjaXR5OjEiIC8+PC9zdmc+)}textarea{padding-bottom:.6rem;padding-top:.6rem;min-height:6.5rem}label,legend{font-size:1.6rem;font-weight:700;display:block;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type='checkbox'],input[type='radio']{display:inline}.label-inline{font-weight:normal;display:inline-block;margin-left:.5rem}.container{margin:0 auto;max-width:112rem;padding:0 2rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row .row-wrap{flex-wrap:wrap}.row .row-no-padding{padding:0}.row .row-no-padding>.column{padding:0}.row .row-top{align-items:flex-start}.row .row-bottom{align-items:flex-end}.row .row-center{align-items:center}.row .row-stretch{align-items:stretch}.row .row-baseline{align-items:baseline}.row .column{display:block;flex:1;margin-left:0;max-width:100%;width:100%}.row .column .col-top{align-self:flex-start}.row .column .col-bottom{align-self:flex-end}.row .column .col-center{align-self:center}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}@media (min-width: 40rem){.row{flex-direction:row;margin-left:-1rem;width:calc(100% + 2.0rem)}.row .column{margin-bottom:inherit;padding:0 1rem}}a{color:#9b4dca;text-decoration:none}a:hover{color:#606c76}dl,ol,ul{margin-top:0;padding-left:0}dl ul,dl ol,ol ul,ol ol,ul ul,ul ol{font-size:90%;margin:1.5rem 0 1.5rem 3rem}dl{list-style:none}ul{list-style:circle inside}ol{list-style:decimal inside}dt,dd,li{margin-bottom:1rem}.button,button{margin-bottom:1rem}input,textarea,select,fieldset{margin-bottom:1.5rem}pre,blockquote,dl,figure,table,p,ul,ol,form{margin-bottom:2.5rem}table{width:100%}th,td{border-bottom:.1rem solid #e1e1e1;padding:1.2rem 1.5rem;text-align:left}th:first-child,td:first-child{padding-left:0}th:last-child,td:last-child{padding-right:0}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;margin-bottom:2rem;margin-top:0}h1{font-size:4rem;letter-spacing:-0.1rem;line-height:1.2}h2{font-size:3.6rem;letter-spacing:-0.1rem;line-height:1.25}h3{font-size:3rem;letter-spacing:-0.1rem;line-height:1.3}h4{font-size:2.4rem;letter-spacing:-0.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-0.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}@media (min-width: 40rem){h1{font-size:5rem}h2{font-size:4.2rem}h3{font-size:3.6rem}h4{font-size:3rem}h5{font-size:2.4rem}h6{font-size:1.5rem}}.float-right{float:right}.float-left{float:left}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{content:"";display:table}.clearfix:after{clear:both} 11 | 12 | /*# sourceMappingURL=milligram.min.css.map */ -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/js/axios.min.js: -------------------------------------------------------------------------------- 1 | /* axios v0.15.3 | (c) 2016 by Matt Zabriskie */ 2 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(4),a=n(5),u=r(a);u.Axios=i,u.create=function(e){return r(o.merge(a,e))},u.Cancel=n(22),u.CancelToken=n(23),u.isCancel=n(19),u.all=function(e){return Promise.all(e)},u.spread=n(24),e.exports=u,e.exports.default=u},function(e,t,n){"use strict";function r(e){return"[object Array]"===C.call(e)}function o(e){return"[object ArrayBuffer]"===C.call(e)}function s(e){return"undefined"!=typeof FormData&&e instanceof FormData}function i(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function a(e){return"string"==typeof e}function u(e){return"number"==typeof e}function c(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===C.call(e)}function d(e){return"[object File]"===C.call(e)}function l(e){return"[object Blob]"===C.call(e)}function h(e){return"[object Function]"===C.call(e)}function m(e){return f(e)&&h(e.pipe)}function y(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function w(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function g(){return"undefined"!=typeof window&&"undefined"!=typeof document&&"function"==typeof document.createElement}function v(e,t){if(null!==e&&"undefined"!=typeof e)if("object"==typeof e||r(e)||(e=[e]),r(e))for(var n=0,o=e.length;n=200&&e<300}};c.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){c.headers[e]={}}),s.forEach(["post","put","patch"],function(e){c.headers[e]=s.merge(u)}),e.exports=c},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(8),s=n(11),i=n(12),a=n(13),u=n(9),c="undefined"!=typeof window&&window.btoa&&window.btoa.bind(window)||n(14);e.exports=function(e){return new Promise(function(t,f){var p=e.data,d=e.headers;r.isFormData(p)&&delete d["Content-Type"];var l=new XMLHttpRequest,h="onreadystatechange",m=!1;if("undefined"==typeof window||!window.XDomainRequest||"withCredentials"in l||a(e.url)||(l=new window.XDomainRequest,h="onload",m=!0,l.onprogress=function(){},l.ontimeout=function(){}),e.auth){var y=e.auth.username||"",w=e.auth.password||"";d.Authorization="Basic "+c(y+":"+w)}if(l.open(e.method.toUpperCase(),s(e.url,e.params,e.paramsSerializer),!0),l.timeout=e.timeout,l[h]=function(){if(l&&(4===l.readyState||m)&&(0!==l.status||l.responseURL&&0===l.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in l?i(l.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?l.response:l.responseText,s={data:r,status:1223===l.status?204:l.status,statusText:1223===l.status?"No Content":l.statusText,headers:n,config:e,request:l};o(t,f,s),l=null}},l.onerror=function(){f(u("Network Error",e)),l=null},l.ontimeout=function(){f(u("timeout of "+e.timeout+"ms exceeded",e,"ECONNABORTED")),l=null},r.isStandardBrowserEnv()){var g=n(15),v=(e.withCredentials||a(e.url))&&e.xsrfCookieName?g.read(e.xsrfCookieName):void 0;v&&(d[e.xsrfHeaderName]=v)}if("setRequestHeader"in l&&r.forEach(d,function(e,t){"undefined"==typeof p&&"content-type"===t.toLowerCase()?delete d[t]:l.setRequestHeader(t,e)}),e.withCredentials&&(l.withCredentials=!0),e.responseType)try{l.responseType=e.responseType}catch(e){if("json"!==l.responseType)throw e}"function"==typeof e.onDownloadProgress&&l.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&l.upload&&l.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){l&&(l.abort(),f(e),l=null)}),void 0===p&&(p=null),l.send(p)})}},function(e,t,n){"use strict";var r=n(9);e.exports=function(e,t,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?t(r("Request failed with status code "+n.status,n.config,null,n)):e(n)}},function(e,t,n){"use strict";var r=n(10);e.exports=function(e,t,n,o){var s=new Error(e);return r(s,t,n,o)}},function(e,t){"use strict";e.exports=function(e,t,n,r){return e.config=t,n&&(e.code=n),e.response=r,e}},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)&&(t+="[]"),o.isArray(e)||(e=[e]),o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}return s&&(e+=(e.indexOf("?")===-1?"?":"&")+s),e}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e){var t,n,o,s={};return e?(r.forEach(e.split("\n"),function(e){o=e.indexOf(":"),t=r.trim(e.substr(0,o)).toLowerCase(),n=r.trim(e.substr(o+1)),t&&(s[t]=s[t]?s[t]+", "+n:n)}),s):s}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t){"use strict";function n(){this.message="String contains an invalid character"}function r(e){for(var t,r,s=String(e),i="",a=0,u=o;s.charAt(0|a)||(u="=",a%1);i+=u.charAt(63&t>>8-a%1*8)){if(r=s.charCodeAt(a+=.75),r>255)throw new n;t=t<<8|r}return i}var o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";n.prototype=new Error,n.prototype.code=5,n.prototype.name="InvalidCharacterError",e.exports=r},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,s,i){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(s)&&a.push("domain="+s),i===!0&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),s=n(18),i=n(19),a=n(5);e.exports=function(e){r(e),e.headers=e.headers||{},e.data=s(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||a.adapter;return t(e).then(function(t){return r(e),t.data=s(t.data,t.headers,e.transformResponse),t},function(t){return i(t)||(r(e),t&&t.response&&(t.response.data=s(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t){"use strict";e.exports=function(e,t){return e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,"")}},function(e,t){"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,n){"use strict";function r(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(22);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e,t=new r(function(t){e=t});return{token:t,cancel:e}},e.exports=r},function(e,t){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}}])}); 3 | //# sourceMappingURL=axios.min.map -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/js/react/app.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import {render} from 'react-dom' 3 | 4 | class Apartments extends Component { 5 | 6 | constructor(props) { 7 | super(props); 8 | 9 | this.state = { 10 | apartments: [], 11 | }; 12 | } 13 | 14 | componentDidMount() { 15 | 16 | if(this.props.state.fetchMore){ 17 | 18 | console.log('loading more items from React app'); 19 | 20 | axios.get('/api') 21 | .then(res => { 22 | var apartments = res.data.apartments; 23 | 24 | this.setState({ apartments }); 25 | }); 26 | 27 | } 28 | } 29 | 30 | renderRows(apartment) { 31 | 32 | return 33 | 34 | { apartment.streetaddress }
35 | { apartment.city }
36 | { apartment.zipcode } 37 | 38 | { apartment.country } 39 | { apartment.buildyear } 40 | 41 | } 42 | 43 | render() { 44 | return
45 |

Hello from React

46 | 47 | 48 | {this.props.state.apartments.map(this.renderRows)} 49 | 50 |
51 |
52 | 53 | } 54 | } 55 | 56 | render(, document.getElementById('app')); -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/js/react/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/js/react/dist/manifest.d41d8cd9.js: -------------------------------------------------------------------------------- 1 | !function(e){function t(n){if(r[n])return r[n].exports;var a=r[n]={exports:{},id:n,loaded:!1};return e[n].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n=window.webpackJsonp;window.webpackJsonp=function(p,o){for(var l,c,s=0,i=[];s 3 | /// 4 | 5 | 6 | async function initTsApp(){ 7 | 8 | if (initialAppState.fetchMore) { 9 | 10 | console.log('loading more items from Vanilla JS app'); 11 | 12 | let apiResponse = await axios.get('/api'); 13 | 14 | let apartments = apiResponse.data.apartments; 15 | 16 | var output = ''; 17 | 18 | for (let j in apartments) { 19 | 20 | let apartment = apartments[j]; 21 | 22 | output += ` 23 | 24 | 25 | ${ apartment.streetaddress }
26 | ${ apartment.city }
27 | ${ apartment.zipcode } 28 | 29 | ${ apartment.country } 30 | ${ apartment.buildyear } 31 | 32 | `; 33 | 34 | } 35 | 36 | let newRows = document.createElement('tbody'); 37 | newRows.innerHTML = output; 38 | 39 | document.querySelector('#ts-app').appendChild(newRows); 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/js/typescript/appstate.d.ts: -------------------------------------------------------------------------------- 1 | interface AppState { 2 | 3 | sortBy: string; 4 | selectedCountry: string; 5 | apartments: ApartmentEntity[]; 6 | fetchMore: boolean; 7 | 8 | } 9 | 10 | interface ApartmentEntity { 11 | 12 | id: number; 13 | streetaddress: string; 14 | city: string; 15 | zipcode: string; 16 | country: string; 17 | buildyear: number; 18 | size: number; 19 | 20 | } 21 | 22 | declare var appState: AppState; 23 | declare var initialAppState: AppState; 24 | -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/js/typescript/axios.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for axios 0.8.1 2 | // Project: https://github.com/mzabriskie/axios 3 | // Definitions by: Marcel Buesing 4 | 5 | declare module Axios { 6 | 7 | interface IThenable { 8 | then(onFulfilled?: (value: R) => U | IThenable, onRejected?: (error: any) => U | IThenable): IThenable; 9 | then(onFulfilled?: (value: R) => U | IThenable, onRejected?: (error: any) => void): IThenable; 10 | } 11 | 12 | interface IPromise extends IThenable { 13 | then(onFulfilled?: (value: R) => U | IThenable, onRejected?: (error: any) => U | IThenable): IPromise; 14 | then(onFulfilled?: (value: R) => U | IThenable, onRejected?: (error: any) => void): IPromise; 15 | catch(onRejected?: (error: any) => U | IThenable): IPromise; 16 | } 17 | 18 | /** 19 | * HTTP Basic auth details 20 | */ 21 | interface AxiosHttpBasicAuth { 22 | username: string; 23 | password: string; 24 | } 25 | 26 | /** 27 | * Common axios XHR config interface 28 | * - request body data type 29 | */ 30 | interface AxiosXHRConfigBase { 31 | /** 32 | * will be prepended to `url` unless `url` is absolute. 33 | * It can be convenient to set `baseURL` for an instance 34 | * of axios to pass relative URLs to methods of that instance. 35 | */ 36 | baseURL?: string; 37 | 38 | /** 39 | * custom headers to be sent 40 | */ 41 | headers?: Object; 42 | 43 | /** 44 | * URL parameters to be sent with the request 45 | */ 46 | params?: Object; 47 | 48 | /** 49 | * optional function in charge of serializing `params` 50 | * (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/) 51 | */ 52 | paramsSerializer?: (params: Object) => string; 53 | 54 | /** 55 | * specifies the number of milliseconds before the request times out. 56 | * If the request takes longer than `timeout`, the request will be aborted. 57 | */ 58 | timeout?: number; 59 | 60 | /** 61 | * indicates whether or not cross-site Access-Control requests 62 | * should be made using credentials 63 | */ 64 | withCredentials?: boolean; 65 | 66 | /** 67 | * indicates that HTTP Basic auth should be used, and supplies 68 | * credentials. This will set an `Authorization` header, 69 | * overwriting any existing `Authorization` custom headers you have 70 | * set using `headers`. 71 | */ 72 | auth?: AxiosHttpBasicAuth; 73 | 74 | /** 75 | * indicates the type of data that the server will respond with 76 | * options are 'arraybuffer', 'blob', 'document', 'json', 'text' 77 | */ 78 | responseType?: string; 79 | 80 | /** 81 | * name of the cookie to use as a value for xsrf token 82 | */ 83 | xsrfCookieName?: string; 84 | 85 | /** 86 | * name of the http header that carries the xsrf token value 87 | */ 88 | xsrfHeaderName?: string; 89 | 90 | /** 91 | * Change the request data before it is sent to the server. 92 | * This is only applicable for request methods 'PUT', 'POST', and 'PATCH' 93 | * The last function in the array must return a string or an ArrayBuffer 94 | */ 95 | transformRequest?: ((data: T) => U) | [(data: T) => U]; 96 | 97 | /** 98 | * change the response data to be made before it is passed to then/catch 99 | */ 100 | transformResponse?: (data: T) => U; 101 | } 102 | 103 | /** 104 | * - request body data type 105 | */ 106 | interface AxiosXHRConfig extends AxiosXHRConfigBase { 107 | /** 108 | * server URL that will be used for the request, options are: 109 | * GET, PUT, POST, DELETE, CONNECT, HEAD, OPTIONS, TRACE, PATCH 110 | */ 111 | url: string; 112 | 113 | /** 114 | * request method to be used when making the request 115 | */ 116 | method?: string; 117 | 118 | /** 119 | * data to be sent as the request body 120 | * Only applicable for request methods 'PUT', 'POST', and 'PATCH' 121 | * When no `transformRequest` is set, must be a string, an ArrayBuffer or a hash 122 | */ 123 | data?: T; 124 | } 125 | 126 | /** 127 | * - expected response type, 128 | * - request body data type 129 | */ 130 | interface AxiosXHR { 131 | /** 132 | * Response that was provided by the server 133 | */ 134 | data: T; 135 | 136 | /** 137 | * HTTP status code from the server response 138 | */ 139 | status: number; 140 | 141 | /** 142 | * HTTP status message from the server response 143 | */ 144 | statusText: string; 145 | 146 | /** 147 | * headers that the server responded with 148 | */ 149 | headers: Object; 150 | 151 | /** 152 | * config that was provided to `axios` for the request 153 | */ 154 | config: AxiosXHRConfig; 155 | } 156 | 157 | interface Interceptor { 158 | /** 159 | * intercept request before it is sent 160 | */ 161 | request: RequestInterceptor; 162 | 163 | /** 164 | * intercept response of request when it is received. 165 | */ 166 | response: ResponseInterceptor 167 | } 168 | 169 | interface RequestInterceptor { 170 | /** 171 | * - request body data type 172 | */ 173 | use(fn: (config: AxiosXHRConfig) => AxiosXHRConfig): void; 174 | } 175 | 176 | interface ResponseInterceptor { 177 | /** 178 | * - expected response type 179 | */ 180 | use(fn: (config: AxiosXHR) => AxiosXHR): void; 181 | } 182 | 183 | /** 184 | * - expected response type, 185 | * - request body data type 186 | */ 187 | interface AxiosInstance { 188 | 189 | /** 190 | * Send request as configured 191 | */ 192 | (config: AxiosXHRConfig): IPromise>; 193 | 194 | /** 195 | * Send request as configured 196 | */ 197 | new (config: AxiosXHRConfig): IPromise>; 198 | 199 | /** 200 | * Send request as configured 201 | */ 202 | request(config: AxiosXHRConfig): IPromise>; 203 | 204 | /** 205 | * intercept requests or responses before they are handled by then or catch 206 | */ 207 | interceptors: Interceptor; 208 | 209 | /** 210 | * equivalent to `Promise.all` 211 | */ 212 | all(values: [T1 | IPromise>, T2 | IPromise>, T3 | IPromise>, T4 | IPromise>, T5 | IPromise>, T6 | IPromise>, T7 | IPromise>, T8 | IPromise>, T9 | IPromise>, T10 | IPromise>]): IPromise<[AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR]>; 213 | all(values: [T1 | IPromise>, T2 | IPromise>, T3 | IPromise>, T4 | IPromise>, T5 | IPromise>, T6 | IPromise>, T7 | IPromise>, T8 | IPromise>, T9 | IPromise>]): IPromise<[AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR]>; 214 | all(values: [T1 | IPromise>, T2 | IPromise>, T3 | IPromise>, T4 | IPromise>, T5 | IPromise>, T6 | IPromise>, T7 | IPromise>, T8 | IPromise>]): IPromise<[AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR]>; 215 | all(values: [T1 | IPromise>, T2 | IPromise>, T3 | IPromise>, T4 | IPromise>, T5 | IPromise>, T6 | IPromise>, T7 | IPromise>]): IPromise<[AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR]>; 216 | all(values: [T1 | IPromise>, T2 | IPromise>, T3 | IPromise>, T4 | IPromise>, T5 | IPromise>, T6 | IPromise>]): IPromise<[AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR]>; 217 | all(values: [T1 | IPromise>, T2 | IPromise>, T3 | IPromise>, T4 | IPromise>, T5 | IPromise>]): IPromise<[AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR]>; 218 | all(values: [T1 | IPromise>, T2 | IPromise>, T3 | IPromise>, T4 | IPromise>]): IPromise<[AxiosXHR, AxiosXHR, AxiosXHR, AxiosXHR]>; 219 | all(values: [T1 | IPromise>, T2 | IPromise>, T3 | IPromise>]): IPromise<[AxiosXHR, AxiosXHR, AxiosXHR]>; 220 | all(values: [T1 | IPromise>, T2 | IPromise>]): IPromise<[AxiosXHR, AxiosXHR]>; 221 | 222 | /** 223 | * spread array parameter to `fn`. 224 | * note: alternative to `spread`, destructuring assignment. 225 | */ 226 | spread(fn: (t1: T1, t2: T2) => U): (arr: ([T1, T2])) => U; 227 | 228 | /** 229 | * convenience alias, method = GET 230 | */ 231 | get(url: string, config?: AxiosXHRConfigBase): IPromise>; 232 | 233 | 234 | /** 235 | * convenience alias, method = DELETE 236 | */ 237 | delete(url: string, config?: AxiosXHRConfigBase): IPromise>; 238 | 239 | /** 240 | * convenience alias, method = HEAD 241 | */ 242 | head(url: string, config?: AxiosXHRConfigBase): IPromise>; 243 | 244 | /** 245 | * convenience alias, method = POST 246 | */ 247 | post(url: string, data?: any, config?: AxiosXHRConfigBase): IPromise>; 248 | 249 | /** 250 | * convenience alias, method = PUT 251 | */ 252 | put(url: string, data?: any, config?: AxiosXHRConfigBase): IPromise>; 253 | 254 | /** 255 | * convenience alias, method = PATCH 256 | */ 257 | patch(url: string, data?: any, config?: AxiosXHRConfigBase): IPromise>; 258 | } 259 | 260 | /** 261 | * - expected response type, 262 | */ 263 | interface AxiosStatic extends AxiosInstance { 264 | /** 265 | * create a new instance of axios with a custom config 266 | */ 267 | create(config: AxiosXHRConfigBase): AxiosInstance; 268 | } 269 | } 270 | 271 | declare var axios: Axios.AxiosStatic; 272 | 273 | declare module "axios" { 274 | export = axios; 275 | } 276 | -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/js/typescript/dist/app.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | return new (P || (P = Promise))(function (resolve, reject) { 3 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 4 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 5 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } 6 | step((generator = generator.apply(thisArg, _arguments)).next()); 7 | }); 8 | }; 9 | function initTsApp() { 10 | return __awaiter(this, void 0, void 0, function* () { 11 | if (initialAppState.fetchMore) { 12 | console.log('loading more items from Vanilla JS app'); 13 | let apiResponse = yield axios.get('/api'); 14 | let apartments = apiResponse.data.apartments; 15 | var output = ''; 16 | for (let j in apartments) { 17 | let apartment = apartments[j]; 18 | output += ` 19 | 20 | 21 | ${apartment.streetaddress}
22 | ${apartment.city}
23 | ${apartment.zipcode} 24 | 25 | ${apartment.country} 26 | ${apartment.buildyear} 27 | 28 | `; 29 | } 30 | let newRows = document.createElement('tbody'); 31 | newRows.innerHTML = output; 32 | document.querySelector('#ts-app').appendChild(newRows); 33 | } 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/js/typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "declaration": false, 6 | "noImplicitAny": false, 7 | "removeComments": true, 8 | "experimentalDecorators": true, 9 | "noLib": false, 10 | "jsx": "react", 11 | "outDir": "dist" 12 | }, 13 | "exclude": [] 14 | } -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/js/vue/app.js: -------------------------------------------------------------------------------- 1 | // create constructor 2 | var ApartmentListing = Vue.extend({ 3 | template: ` 4 |
5 |

Hello from Vue

6 | 7 | 8 | 13 | 14 | 15 | 16 |
9 | {{ apartment.streetaddress }}
10 | {{ apartment.city }}
11 | {{ apartment.zipcode }} 12 |
{{ apartment.country }}{{ apartment.buildyear }}
17 |
18 | `, 19 | data: function () { 20 | 21 | let vueAppState = initialAppState; 22 | 23 | return vueAppState; 24 | }, 25 | 26 | created: function () { 27 | 28 | if(this.fetchMore) { 29 | 30 | console.log('loading more items from Vue app'); 31 | 32 | var that = this; 33 | 34 | axios.get('/api') 35 | .then(function (response) { 36 | 37 | for (var i in response.data.apartments) { 38 | that.apartments.push(response.data.apartments[i]); 39 | } 40 | 41 | }) 42 | .catch(function (error) { 43 | console.log(error); 44 | }); 45 | 46 | } 47 | 48 | 49 | } 50 | }); 51 | // create an instance of ApartmentListing and mount it on an element 52 | new ApartmentListing().$mount('#vue-app'); -------------------------------------------------------------------------------- /src/AppBundle/Resources/public/js/vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "declaration": false, 6 | "noImplicitAny": false, 7 | "removeComments": true, 8 | "experimentalDecorators": true, 9 | "noLib": false, 10 | "jsx": "react", 11 | "outDir": "dist" 12 | }, 13 | "exclude": [] 14 | } -------------------------------------------------------------------------------- /src/AppBundle/State/AppState.php: -------------------------------------------------------------------------------- 1 | serialize($this, 'json'); 22 | 23 | } 24 | 25 | /** 26 | * @return string 27 | */ 28 | public function getSortBy() 29 | { 30 | return $this->sortBy; 31 | } 32 | 33 | /** 34 | * @param string $sortBy 35 | */ 36 | public function setSortBy($sortBy) 37 | { 38 | $this->sortBy = $sortBy; 39 | } 40 | 41 | /** 42 | * @return array 43 | */ 44 | public function getApartments() 45 | { 46 | return $this->apartments; 47 | } 48 | 49 | /** 50 | * @param array $apartments 51 | */ 52 | public function setApartments($apartments) 53 | { 54 | $this->apartments = $apartments; 55 | } 56 | 57 | /** 58 | * @return bool 59 | */ 60 | public function isSelectedCountry() 61 | { 62 | return $this->selectedCountry; 63 | } 64 | 65 | /** 66 | * @param bool $selectedCountry 67 | */ 68 | public function setSelectedCountry($selectedCountry) 69 | { 70 | $this->selectedCountry = $selectedCountry; 71 | } 72 | 73 | /** 74 | * @return bool 75 | */ 76 | public function isFetchMore() 77 | { 78 | return $this->fetchMore; 79 | } 80 | 81 | /** 82 | * @param bool $fetchMore 83 | */ 84 | public function setFetchMore($fetchMore) 85 | { 86 | $this->fetchMore = $fetchMore; 87 | } 88 | 89 | 90 | 91 | } -------------------------------------------------------------------------------- /tests/AppBundle/Controller/DefaultControllerTest.php: -------------------------------------------------------------------------------- 1 | request('GET', '/'); 14 | 15 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); 16 | $this->assertContains('Welcome to Symfony', $crawler->filter('#container h1')->text()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /var/SymfonyRequirements.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /* 13 | * Users of PHP 5.2 should be able to run the requirements checks. 14 | * This is why the file and all classes must be compatible with PHP 5.2+ 15 | * (e.g. not using namespaces and closures). 16 | * 17 | * ************** CAUTION ************** 18 | * 19 | * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of 20 | * the installation/update process. The original file resides in the 21 | * SensioDistributionBundle. 22 | * 23 | * ************** CAUTION ************** 24 | */ 25 | 26 | /** 27 | * Represents a single PHP requirement, e.g. an installed extension. 28 | * It can be a mandatory requirement or an optional recommendation. 29 | * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration. 30 | * 31 | * @author Tobias Schultze 32 | */ 33 | class Requirement 34 | { 35 | private $fulfilled; 36 | private $testMessage; 37 | private $helpText; 38 | private $helpHtml; 39 | private $optional; 40 | 41 | /** 42 | * Constructor that initializes the requirement. 43 | * 44 | * @param bool $fulfilled Whether the requirement is fulfilled 45 | * @param string $testMessage The message for testing the requirement 46 | * @param string $helpHtml The help text formatted in HTML for resolving the problem 47 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 48 | * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement 49 | */ 50 | public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false) 51 | { 52 | $this->fulfilled = (bool) $fulfilled; 53 | $this->testMessage = (string) $testMessage; 54 | $this->helpHtml = (string) $helpHtml; 55 | $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText; 56 | $this->optional = (bool) $optional; 57 | } 58 | 59 | /** 60 | * Returns whether the requirement is fulfilled. 61 | * 62 | * @return bool true if fulfilled, otherwise false 63 | */ 64 | public function isFulfilled() 65 | { 66 | return $this->fulfilled; 67 | } 68 | 69 | /** 70 | * Returns the message for testing the requirement. 71 | * 72 | * @return string The test message 73 | */ 74 | public function getTestMessage() 75 | { 76 | return $this->testMessage; 77 | } 78 | 79 | /** 80 | * Returns the help text for resolving the problem. 81 | * 82 | * @return string The help text 83 | */ 84 | public function getHelpText() 85 | { 86 | return $this->helpText; 87 | } 88 | 89 | /** 90 | * Returns the help text formatted in HTML. 91 | * 92 | * @return string The HTML help 93 | */ 94 | public function getHelpHtml() 95 | { 96 | return $this->helpHtml; 97 | } 98 | 99 | /** 100 | * Returns whether this is only an optional recommendation and not a mandatory requirement. 101 | * 102 | * @return bool true if optional, false if mandatory 103 | */ 104 | public function isOptional() 105 | { 106 | return $this->optional; 107 | } 108 | } 109 | 110 | /** 111 | * Represents a PHP requirement in form of a php.ini configuration. 112 | * 113 | * @author Tobias Schultze 114 | */ 115 | class PhpIniRequirement extends Requirement 116 | { 117 | /** 118 | * Constructor that initializes the requirement. 119 | * 120 | * @param string $cfgName The configuration name used for ini_get() 121 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, 122 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement 123 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. 124 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. 125 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. 126 | * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) 127 | * @param string|null $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived) 128 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 129 | * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement 130 | */ 131 | public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false) 132 | { 133 | $cfgValue = ini_get($cfgName); 134 | 135 | if (is_callable($evaluation)) { 136 | if (null === $testMessage || null === $helpHtml) { 137 | throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.'); 138 | } 139 | 140 | $fulfilled = call_user_func($evaluation, $cfgValue); 141 | } else { 142 | if (null === $testMessage) { 143 | $testMessage = sprintf('%s %s be %s in php.ini', 144 | $cfgName, 145 | $optional ? 'should' : 'must', 146 | $evaluation ? 'enabled' : 'disabled' 147 | ); 148 | } 149 | 150 | if (null === $helpHtml) { 151 | $helpHtml = sprintf('Set %s to %s in php.ini*.', 152 | $cfgName, 153 | $evaluation ? 'on' : 'off' 154 | ); 155 | } 156 | 157 | $fulfilled = $evaluation == $cfgValue; 158 | } 159 | 160 | parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional); 161 | } 162 | } 163 | 164 | /** 165 | * A RequirementCollection represents a set of Requirement instances. 166 | * 167 | * @author Tobias Schultze 168 | */ 169 | class RequirementCollection implements IteratorAggregate 170 | { 171 | /** 172 | * @var Requirement[] 173 | */ 174 | private $requirements = array(); 175 | 176 | /** 177 | * Gets the current RequirementCollection as an Iterator. 178 | * 179 | * @return Traversable A Traversable interface 180 | */ 181 | public function getIterator() 182 | { 183 | return new ArrayIterator($this->requirements); 184 | } 185 | 186 | /** 187 | * Adds a Requirement. 188 | * 189 | * @param Requirement $requirement A Requirement instance 190 | */ 191 | public function add(Requirement $requirement) 192 | { 193 | $this->requirements[] = $requirement; 194 | } 195 | 196 | /** 197 | * Adds a mandatory requirement. 198 | * 199 | * @param bool $fulfilled Whether the requirement is fulfilled 200 | * @param string $testMessage The message for testing the requirement 201 | * @param string $helpHtml The help text formatted in HTML for resolving the problem 202 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 203 | */ 204 | public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null) 205 | { 206 | $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false)); 207 | } 208 | 209 | /** 210 | * Adds an optional recommendation. 211 | * 212 | * @param bool $fulfilled Whether the recommendation is fulfilled 213 | * @param string $testMessage The message for testing the recommendation 214 | * @param string $helpHtml The help text formatted in HTML for resolving the problem 215 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 216 | */ 217 | public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null) 218 | { 219 | $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true)); 220 | } 221 | 222 | /** 223 | * Adds a mandatory requirement in form of a php.ini configuration. 224 | * 225 | * @param string $cfgName The configuration name used for ini_get() 226 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, 227 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement 228 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. 229 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. 230 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. 231 | * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) 232 | * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived) 233 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 234 | */ 235 | public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) 236 | { 237 | $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false)); 238 | } 239 | 240 | /** 241 | * Adds an optional recommendation in form of a php.ini configuration. 242 | * 243 | * @param string $cfgName The configuration name used for ini_get() 244 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, 245 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement 246 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. 247 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. 248 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. 249 | * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) 250 | * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived) 251 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 252 | */ 253 | public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) 254 | { 255 | $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true)); 256 | } 257 | 258 | /** 259 | * Adds a requirement collection to the current set of requirements. 260 | * 261 | * @param RequirementCollection $collection A RequirementCollection instance 262 | */ 263 | public function addCollection(RequirementCollection $collection) 264 | { 265 | $this->requirements = array_merge($this->requirements, $collection->all()); 266 | } 267 | 268 | /** 269 | * Returns both requirements and recommendations. 270 | * 271 | * @return Requirement[] 272 | */ 273 | public function all() 274 | { 275 | return $this->requirements; 276 | } 277 | 278 | /** 279 | * Returns all mandatory requirements. 280 | * 281 | * @return Requirement[] 282 | */ 283 | public function getRequirements() 284 | { 285 | $array = array(); 286 | foreach ($this->requirements as $req) { 287 | if (!$req->isOptional()) { 288 | $array[] = $req; 289 | } 290 | } 291 | 292 | return $array; 293 | } 294 | 295 | /** 296 | * Returns the mandatory requirements that were not met. 297 | * 298 | * @return Requirement[] 299 | */ 300 | public function getFailedRequirements() 301 | { 302 | $array = array(); 303 | foreach ($this->requirements as $req) { 304 | if (!$req->isFulfilled() && !$req->isOptional()) { 305 | $array[] = $req; 306 | } 307 | } 308 | 309 | return $array; 310 | } 311 | 312 | /** 313 | * Returns all optional recommendations. 314 | * 315 | * @return Requirement[] 316 | */ 317 | public function getRecommendations() 318 | { 319 | $array = array(); 320 | foreach ($this->requirements as $req) { 321 | if ($req->isOptional()) { 322 | $array[] = $req; 323 | } 324 | } 325 | 326 | return $array; 327 | } 328 | 329 | /** 330 | * Returns the recommendations that were not met. 331 | * 332 | * @return Requirement[] 333 | */ 334 | public function getFailedRecommendations() 335 | { 336 | $array = array(); 337 | foreach ($this->requirements as $req) { 338 | if (!$req->isFulfilled() && $req->isOptional()) { 339 | $array[] = $req; 340 | } 341 | } 342 | 343 | return $array; 344 | } 345 | 346 | /** 347 | * Returns whether a php.ini configuration is not correct. 348 | * 349 | * @return bool php.ini configuration problem? 350 | */ 351 | public function hasPhpIniConfigIssue() 352 | { 353 | foreach ($this->requirements as $req) { 354 | if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) { 355 | return true; 356 | } 357 | } 358 | 359 | return false; 360 | } 361 | 362 | /** 363 | * Returns the PHP configuration file (php.ini) path. 364 | * 365 | * @return string|false php.ini file path 366 | */ 367 | public function getPhpIniConfigPath() 368 | { 369 | return get_cfg_var('cfg_file_path'); 370 | } 371 | } 372 | 373 | /** 374 | * This class specifies all requirements and optional recommendations that 375 | * are necessary to run the Symfony Standard Edition. 376 | * 377 | * @author Tobias Schultze 378 | * @author Fabien Potencier 379 | */ 380 | class SymfonyRequirements extends RequirementCollection 381 | { 382 | const LEGACY_REQUIRED_PHP_VERSION = '5.3.3'; 383 | const REQUIRED_PHP_VERSION = '5.5.9'; 384 | 385 | /** 386 | * Constructor that initializes the requirements. 387 | */ 388 | public function __construct() 389 | { 390 | /* mandatory requirements follow */ 391 | 392 | $installedPhpVersion = phpversion(); 393 | $requiredPhpVersion = $this->getPhpRequiredVersion(); 394 | 395 | $this->addRecommendation( 396 | $requiredPhpVersion, 397 | 'Vendors should be installed in order to check all requirements.', 398 | 'Run the composer install command.', 399 | 'Run the "composer install" command.' 400 | ); 401 | 402 | if (false !== $requiredPhpVersion) { 403 | $this->addRequirement( 404 | version_compare($installedPhpVersion, $requiredPhpVersion, '>='), 405 | sprintf('PHP version must be at least %s (%s installed)', $requiredPhpVersion, $installedPhpVersion), 406 | sprintf('You are running PHP version "%s", but Symfony needs at least PHP "%s" to run. 407 | Before using Symfony, upgrade your PHP installation, preferably to the latest version.', 408 | $installedPhpVersion, $requiredPhpVersion), 409 | sprintf('Install PHP %s or newer (installed version is %s)', $requiredPhpVersion, $installedPhpVersion) 410 | ); 411 | } 412 | 413 | $this->addRequirement( 414 | version_compare($installedPhpVersion, '5.3.16', '!='), 415 | 'PHP version must not be 5.3.16 as Symfony won\'t work properly with it', 416 | 'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)' 417 | ); 418 | 419 | $this->addRequirement( 420 | is_dir(__DIR__.'/../vendor/composer'), 421 | 'Vendor libraries must be installed', 422 | 'Vendor libraries are missing. Install composer following instructions from http://getcomposer.org/. '. 423 | 'Then run "php composer.phar install" to install them.' 424 | ); 425 | 426 | $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache'; 427 | 428 | $this->addRequirement( 429 | is_writable($cacheDir), 430 | 'app/cache/ or var/cache/ directory must be writable', 431 | 'Change the permissions of either "app/cache/" or "var/cache/" directory so that the web server can write into it.' 432 | ); 433 | 434 | $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs'; 435 | 436 | $this->addRequirement( 437 | is_writable($logsDir), 438 | 'app/logs/ or var/logs/ directory must be writable', 439 | 'Change the permissions of either "app/logs/" or "var/logs/" directory so that the web server can write into it.' 440 | ); 441 | 442 | if (version_compare($installedPhpVersion, '7.0.0', '<')) { 443 | $this->addPhpIniRequirement( 444 | 'date.timezone', true, false, 445 | 'date.timezone setting must be set', 446 | 'Set the "date.timezone" setting in php.ini* (like Europe/Paris).' 447 | ); 448 | } 449 | 450 | if (false !== $requiredPhpVersion && version_compare($installedPhpVersion, $requiredPhpVersion, '>=')) { 451 | $timezones = array(); 452 | foreach (DateTimeZone::listAbbreviations() as $abbreviations) { 453 | foreach ($abbreviations as $abbreviation) { 454 | $timezones[$abbreviation['timezone_id']] = true; 455 | } 456 | } 457 | 458 | $this->addRequirement( 459 | isset($timezones[@date_default_timezone_get()]), 460 | sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()), 461 | 'Your default timezone is not supported by PHP. Check for typos in your php.ini file and have a look at the list of deprecated timezones at http://php.net/manual/en/timezones.others.php.' 462 | ); 463 | } 464 | 465 | $this->addRequirement( 466 | function_exists('iconv'), 467 | 'iconv() must be available', 468 | 'Install and enable the iconv extension.' 469 | ); 470 | 471 | $this->addRequirement( 472 | function_exists('json_encode'), 473 | 'json_encode() must be available', 474 | 'Install and enable the JSON extension.' 475 | ); 476 | 477 | $this->addRequirement( 478 | function_exists('session_start'), 479 | 'session_start() must be available', 480 | 'Install and enable the session extension.' 481 | ); 482 | 483 | $this->addRequirement( 484 | function_exists('ctype_alpha'), 485 | 'ctype_alpha() must be available', 486 | 'Install and enable the ctype extension.' 487 | ); 488 | 489 | $this->addRequirement( 490 | function_exists('token_get_all'), 491 | 'token_get_all() must be available', 492 | 'Install and enable the Tokenizer extension.' 493 | ); 494 | 495 | $this->addRequirement( 496 | function_exists('simplexml_import_dom'), 497 | 'simplexml_import_dom() must be available', 498 | 'Install and enable the SimpleXML extension.' 499 | ); 500 | 501 | if (function_exists('apc_store') && ini_get('apc.enabled')) { 502 | if (version_compare($installedPhpVersion, '5.4.0', '>=')) { 503 | $this->addRequirement( 504 | version_compare(phpversion('apc'), '3.1.13', '>='), 505 | 'APC version must be at least 3.1.13 when using PHP 5.4', 506 | 'Upgrade your APC extension (3.1.13+).' 507 | ); 508 | } else { 509 | $this->addRequirement( 510 | version_compare(phpversion('apc'), '3.0.17', '>='), 511 | 'APC version must be at least 3.0.17', 512 | 'Upgrade your APC extension (3.0.17+).' 513 | ); 514 | } 515 | } 516 | 517 | $this->addPhpIniRequirement('detect_unicode', false); 518 | 519 | if (extension_loaded('suhosin')) { 520 | $this->addPhpIniRequirement( 521 | 'suhosin.executor.include.whitelist', 522 | create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'), 523 | false, 524 | 'suhosin.executor.include.whitelist must be configured correctly in php.ini', 525 | 'Add "phar" to suhosin.executor.include.whitelist in php.ini*.' 526 | ); 527 | } 528 | 529 | if (extension_loaded('xdebug')) { 530 | $this->addPhpIniRequirement( 531 | 'xdebug.show_exception_trace', false, true 532 | ); 533 | 534 | $this->addPhpIniRequirement( 535 | 'xdebug.scream', false, true 536 | ); 537 | 538 | $this->addPhpIniRecommendation( 539 | 'xdebug.max_nesting_level', 540 | create_function('$cfgValue', 'return $cfgValue > 100;'), 541 | true, 542 | 'xdebug.max_nesting_level should be above 100 in php.ini', 543 | 'Set "xdebug.max_nesting_level" to e.g. "250" in php.ini* to stop Xdebug\'s infinite recursion protection erroneously throwing a fatal error in your project.' 544 | ); 545 | } 546 | 547 | $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null; 548 | 549 | $this->addRequirement( 550 | null !== $pcreVersion, 551 | 'PCRE extension must be available', 552 | 'Install the PCRE extension (version 8.0+).' 553 | ); 554 | 555 | if (extension_loaded('mbstring')) { 556 | $this->addPhpIniRequirement( 557 | 'mbstring.func_overload', 558 | create_function('$cfgValue', 'return (int) $cfgValue === 0;'), 559 | true, 560 | 'string functions should not be overloaded', 561 | 'Set "mbstring.func_overload" to 0 in php.ini* to disable function overloading by the mbstring extension.' 562 | ); 563 | } 564 | 565 | /* optional recommendations follow */ 566 | 567 | if (file_exists(__DIR__.'/../vendor/composer')) { 568 | require_once __DIR__.'/../vendor/autoload.php'; 569 | 570 | try { 571 | $r = new ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle'); 572 | 573 | $contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php'); 574 | } catch (ReflectionException $e) { 575 | $contents = ''; 576 | } 577 | $this->addRecommendation( 578 | file_get_contents(__FILE__) === $contents, 579 | 'Requirements file should be up-to-date', 580 | 'Your requirements file is outdated. Run composer install and re-check your configuration.' 581 | ); 582 | } 583 | 584 | $this->addRecommendation( 585 | version_compare($installedPhpVersion, '5.3.4', '>='), 586 | 'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions', 587 | 'Your project might malfunction randomly due to PHP bug #52083 ("Notice: Trying to get property of non-object"). Install PHP 5.3.4 or newer.' 588 | ); 589 | 590 | $this->addRecommendation( 591 | version_compare($installedPhpVersion, '5.3.8', '>='), 592 | 'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156', 593 | 'Install PHP 5.3.8 or newer if your project uses annotations.' 594 | ); 595 | 596 | $this->addRecommendation( 597 | version_compare($installedPhpVersion, '5.4.0', '!='), 598 | 'You should not use PHP 5.4.0 due to the PHP bug #61453', 599 | 'Your project might not work properly due to the PHP bug #61453 ("Cannot dump definitions which have method calls"). Install PHP 5.4.1 or newer.' 600 | ); 601 | 602 | $this->addRecommendation( 603 | version_compare($installedPhpVersion, '5.4.11', '>='), 604 | 'When using the logout handler from the Symfony Security Component, you should have at least PHP 5.4.11 due to PHP bug #63379 (as a workaround, you can also set invalidate_session to false in the security logout handler configuration)', 605 | 'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.' 606 | ); 607 | 608 | $this->addRecommendation( 609 | (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<')) 610 | || 611 | version_compare($installedPhpVersion, '5.4.8', '>='), 612 | 'You should use PHP 5.3.18+ or PHP 5.4.8+ to always get nice error messages for fatal errors in the development environment due to PHP bug #61767/#60909', 613 | 'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.' 614 | ); 615 | 616 | if (null !== $pcreVersion) { 617 | $this->addRecommendation( 618 | $pcreVersion >= 8.0, 619 | sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion), 620 | 'PCRE 8.0+ is preconfigured in PHP since 5.3.2 but you are using an outdated version of it. Symfony probably works anyway but it is recommended to upgrade your PCRE extension.' 621 | ); 622 | } 623 | 624 | $this->addRecommendation( 625 | class_exists('DomDocument'), 626 | 'PHP-DOM and PHP-XML modules should be installed', 627 | 'Install and enable the PHP-DOM and the PHP-XML modules.' 628 | ); 629 | 630 | $this->addRecommendation( 631 | function_exists('mb_strlen'), 632 | 'mb_strlen() should be available', 633 | 'Install and enable the mbstring extension.' 634 | ); 635 | 636 | $this->addRecommendation( 637 | function_exists('utf8_decode'), 638 | 'utf8_decode() should be available', 639 | 'Install and enable the XML extension.' 640 | ); 641 | 642 | $this->addRecommendation( 643 | function_exists('filter_var'), 644 | 'filter_var() should be available', 645 | 'Install and enable the filter extension.' 646 | ); 647 | 648 | if (!defined('PHP_WINDOWS_VERSION_BUILD')) { 649 | $this->addRecommendation( 650 | function_exists('posix_isatty'), 651 | 'posix_isatty() should be available', 652 | 'Install and enable the php_posix extension (used to colorize the CLI output).' 653 | ); 654 | } 655 | 656 | $this->addRecommendation( 657 | extension_loaded('intl'), 658 | 'intl extension should be available', 659 | 'Install and enable the intl extension (used for validators).' 660 | ); 661 | 662 | if (extension_loaded('intl')) { 663 | // in some WAMP server installations, new Collator() returns null 664 | $this->addRecommendation( 665 | null !== new Collator('fr_FR'), 666 | 'intl extension should be correctly configured', 667 | 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.' 668 | ); 669 | 670 | // check for compatible ICU versions (only done when you have the intl extension) 671 | if (defined('INTL_ICU_VERSION')) { 672 | $version = INTL_ICU_VERSION; 673 | } else { 674 | $reflector = new ReflectionExtension('intl'); 675 | 676 | ob_start(); 677 | $reflector->info(); 678 | $output = strip_tags(ob_get_clean()); 679 | 680 | preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches); 681 | $version = $matches[1]; 682 | } 683 | 684 | $this->addRecommendation( 685 | version_compare($version, '4.0', '>='), 686 | 'intl ICU version should be at least 4+', 687 | 'Upgrade your intl extension with a newer ICU version (4+).' 688 | ); 689 | 690 | if (class_exists('Symfony\Component\Intl\Intl')) { 691 | $this->addRecommendation( 692 | \Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion(), 693 | sprintf('intl ICU version installed on your system is outdated (%s) and does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()), 694 | 'To get the latest internationalization data upgrade the ICU system package and the intl PHP extension.' 695 | ); 696 | if (\Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion()) { 697 | $this->addRecommendation( 698 | \Symfony\Component\Intl\Intl::getIcuDataVersion() === \Symfony\Component\Intl\Intl::getIcuVersion(), 699 | sprintf('intl ICU version installed on your system (%s) does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()), 700 | 'To avoid internationalization data inconsistencies upgrade the symfony/intl component.' 701 | ); 702 | } 703 | } 704 | 705 | $this->addPhpIniRecommendation( 706 | 'intl.error_level', 707 | create_function('$cfgValue', 'return (int) $cfgValue === 0;'), 708 | true, 709 | 'intl.error_level should be 0 in php.ini', 710 | 'Set "intl.error_level" to "0" in php.ini* to inhibit the messages when an error occurs in ICU functions.' 711 | ); 712 | } 713 | 714 | $accelerator = 715 | (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) 716 | || 717 | (extension_loaded('apc') && ini_get('apc.enabled')) 718 | || 719 | (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable')) 720 | || 721 | (extension_loaded('Zend OPcache') && ini_get('opcache.enable')) 722 | || 723 | (extension_loaded('xcache') && ini_get('xcache.cacher')) 724 | || 725 | (extension_loaded('wincache') && ini_get('wincache.ocenabled')) 726 | ; 727 | 728 | $this->addRecommendation( 729 | $accelerator, 730 | 'a PHP accelerator should be installed', 731 | 'Install and/or enable a PHP accelerator (highly recommended).' 732 | ); 733 | 734 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { 735 | $this->addRecommendation( 736 | $this->getRealpathCacheSize() >= 5 * 1024 * 1024, 737 | 'realpath_cache_size should be at least 5M in php.ini', 738 | 'Setting "realpath_cache_size" to e.g. "5242880" or "5M" in php.ini* may improve performance on Windows significantly in some cases.' 739 | ); 740 | } 741 | 742 | $this->addPhpIniRecommendation('short_open_tag', false); 743 | 744 | $this->addPhpIniRecommendation('magic_quotes_gpc', false, true); 745 | 746 | $this->addPhpIniRecommendation('register_globals', false, true); 747 | 748 | $this->addPhpIniRecommendation('session.auto_start', false); 749 | 750 | $this->addRecommendation( 751 | class_exists('PDO'), 752 | 'PDO should be installed', 753 | 'Install PDO (mandatory for Doctrine).' 754 | ); 755 | 756 | if (class_exists('PDO')) { 757 | $drivers = PDO::getAvailableDrivers(); 758 | $this->addRecommendation( 759 | count($drivers) > 0, 760 | sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'), 761 | 'Install PDO drivers (mandatory for Doctrine).' 762 | ); 763 | } 764 | } 765 | 766 | /** 767 | * Loads realpath_cache_size from php.ini and converts it to int. 768 | * 769 | * (e.g. 16k is converted to 16384 int) 770 | * 771 | * @return int 772 | */ 773 | protected function getRealpathCacheSize() 774 | { 775 | $size = ini_get('realpath_cache_size'); 776 | $size = trim($size); 777 | $unit = ''; 778 | if (!ctype_digit($size)) { 779 | $unit = strtolower(substr($size, -1, 1)); 780 | $size = (int) substr($size, 0, -1); 781 | } 782 | switch ($unit) { 783 | case 'g': 784 | return $size * 1024 * 1024 * 1024; 785 | case 'm': 786 | return $size * 1024 * 1024; 787 | case 'k': 788 | return $size * 1024; 789 | default: 790 | return (int) $size; 791 | } 792 | } 793 | 794 | /** 795 | * Defines PHP required version from Symfony version. 796 | * 797 | * @return string|false The PHP required version or false if it could not be guessed 798 | */ 799 | protected function getPhpRequiredVersion() 800 | { 801 | if (!file_exists($path = __DIR__.'/../composer.lock')) { 802 | return false; 803 | } 804 | 805 | $composerLock = json_decode(file_get_contents($path), true); 806 | foreach ($composerLock['packages'] as $package) { 807 | $name = $package['name']; 808 | if ('symfony/symfony' !== $name && 'symfony/http-kernel' !== $name) { 809 | continue; 810 | } 811 | 812 | return (int) $package['version'][1] > 2 ? self::REQUIRED_PHP_VERSION : self::LEGACY_REQUIRED_PHP_VERSION; 813 | } 814 | 815 | return false; 816 | } 817 | } 818 | -------------------------------------------------------------------------------- /var/cache/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janit/symfony-hybrid-twig-react-vue/a014a00ee2338f2c52591c855c3a6db080dc06d5/var/cache/.gitkeep -------------------------------------------------------------------------------- /var/logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janit/symfony-hybrid-twig-react-vue/a014a00ee2338f2c52591c855c3a6db080dc06d5/var/logs/.gitkeep -------------------------------------------------------------------------------- /var/sessions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janit/symfony-hybrid-twig-react-vue/a014a00ee2338f2c52591c855c3a6db080dc06d5/var/sessions/.gitkeep -------------------------------------------------------------------------------- /web/.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 app.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. "/app" should not resolve 15 | # to the front controller "/app.php" but be rewritten to "/app.php/app". 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 app.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}::$1 ^(/.+)/(.*)::\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:%{HTTP:Authorization}] 36 | 37 | # Redirect to URI without front controller to prevent duplicate content 38 | # (with and without `/app.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 ^app\.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 | RewriteCond %{REQUEST_FILENAME} -f 54 | RewriteRule ^ - [L] 55 | 56 | # Rewrite all other queries to the front controller. 57 | RewriteRule ^ %{ENV:BASE}/app.php [L] 58 | 59 | 60 | 61 | 62 | # When mod_rewrite is not available, we instruct a temporary redirect of 63 | # the start page to the front controller explicitly so that the website 64 | # and the generated links can still be used. 65 | RedirectMatch 302 ^/$ /app.php/ 66 | # RedirectTemp cannot be used instead 67 | 68 | 69 | -------------------------------------------------------------------------------- /web/app.php: -------------------------------------------------------------------------------- 1 | loadClassCache(); 11 | //$kernel = new AppCache($kernel); 12 | 13 | // When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter 14 | //Request::enableHttpMethodParameterOverride(); 15 | $request = Request::createFromGlobals(); 16 | $response = $kernel->handle($request); 17 | $response->send(); 18 | $kernel->terminate($request, $response); 19 | -------------------------------------------------------------------------------- /web/app_dev.php: -------------------------------------------------------------------------------- 1 | loadClassCache(); 27 | $request = Request::createFromGlobals(); 28 | $response = $kernel->handle($request); 29 | $response->send(); 30 | $kernel->terminate($request, $response); 31 | -------------------------------------------------------------------------------- /web/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janit/symfony-hybrid-twig-react-vue/a014a00ee2338f2c52591c855c3a6db080dc06d5/web/apple-touch-icon.png -------------------------------------------------------------------------------- /web/config.php: -------------------------------------------------------------------------------- 1 | getFailedRequirements(); 30 | $minorProblems = $symfonyRequirements->getFailedRecommendations(); 31 | $hasMajorProblems = (bool) count($majorProblems); 32 | $hasMinorProblems = (bool) count($minorProblems); 33 | 34 | ?> 35 | 36 | 37 | 38 | 39 | 40 | Symfony Configuration Checker 41 | 331 | 332 | 333 |
334 |
335 | 338 | 339 | 359 |
360 | 361 |
362 |
363 |
364 |

Configuration Checker

365 |

366 | This script analyzes your system to check whether is 367 | ready to run Symfony applications. 368 |

369 | 370 | 371 |

Major problems

372 |

Major problems have been detected and must be fixed before continuing:

373 |
    374 | 375 |
  1. getTestMessage() ?> 376 |

    getHelpHtml() ?>

    377 |
  2. 378 | 379 |
380 | 381 | 382 | 383 |

Recommendations

384 |

385 | Additionally, toTo enhance your Symfony experience, 386 | it’s recommended that you fix the following: 387 |

388 |
    389 | 390 |
  1. getTestMessage() ?> 391 |

    getHelpHtml() ?>

    392 |
  2. 393 | 394 |
395 | 396 | 397 | hasPhpIniConfigIssue()): ?> 398 |

* 399 | getPhpIniConfigPath()): ?> 400 | Changes to the php.ini file must be done in "getPhpIniConfigPath() ?>". 401 | 402 | To change settings, create a "php.ini". 403 | 404 |

405 | 406 | 407 | 408 |

All checks passed successfully. Your system is ready to run Symfony applications.

409 | 410 | 411 | 416 |
417 |
418 |
419 |
Symfony Standard Edition
420 |
421 | 422 | 423 | -------------------------------------------------------------------------------- /web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janit/symfony-hybrid-twig-react-vue/a014a00ee2338f2c52591c855c3a6db080dc06d5/web/favicon.ico -------------------------------------------------------------------------------- /web/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | # www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449 3 | 4 | User-agent: * 5 | Disallow: 6 | --------------------------------------------------------------------------------