You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	First commit
This commit is contained in:
		
							
								
								
									
										17
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| /app/config/parameters.yml | ||||
| /build/ | ||||
| /phpunit.xml | ||||
| /var/* | ||||
| !/var/cache | ||||
| /var/cache/* | ||||
| !var/cache/.gitkeep | ||||
| !/var/logs | ||||
| /var/logs/* | ||||
| !var/logs/.gitkeep | ||||
| !/var/sessions | ||||
| /var/sessions/* | ||||
| !var/sessions/.gitkeep | ||||
| !var/SymfonyRequirements.php | ||||
| /vendor/ | ||||
| /web/bundles/ | ||||
| *.sublime-workspace | ||||
							
								
								
									
										4
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| notes | ||||
| ===== | ||||
|  | ||||
| A Symfony project created on October 5, 2016, 4:15 pm. | ||||
							
								
								
									
										7
									
								
								app/.htaccess
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/.htaccess
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| <IfModule mod_authz_core.c> | ||||
|     Require all denied | ||||
| </IfModule> | ||||
| <IfModule !mod_authz_core.c> | ||||
|     Order deny,allow | ||||
|     Deny from all | ||||
| </IfModule> | ||||
							
								
								
									
										7
									
								
								app/AppCache.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/AppCache.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| <?php | ||||
|  | ||||
| use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; | ||||
|  | ||||
| class AppCache extends HttpCache | ||||
| { | ||||
| } | ||||
							
								
								
									
										50
									
								
								app/AppKernel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								app/AppKernel.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| <?php | ||||
|  | ||||
| use Symfony\Component\HttpKernel\Kernel; | ||||
| use Symfony\Component\Config\Loader\LoaderInterface; | ||||
|  | ||||
| class AppKernel extends Kernel | ||||
| { | ||||
|     public function registerBundles() | ||||
|     { | ||||
|         $bundles = [ | ||||
|             new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), | ||||
|             new Symfony\Bundle\SecurityBundle\SecurityBundle(), | ||||
|             new Symfony\Bundle\TwigBundle\TwigBundle(), | ||||
|             new Symfony\Bundle\MonologBundle\MonologBundle(), | ||||
|             new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), | ||||
|             new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), | ||||
|             new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), | ||||
|             new AppBundle\AppBundle(), | ||||
|         ]; | ||||
|  | ||||
|         if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { | ||||
|             $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle(); | ||||
|             $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); | ||||
|             $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); | ||||
|             $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); | ||||
|         } | ||||
|  | ||||
|         return $bundles; | ||||
|     } | ||||
|  | ||||
|     public function getRootDir() | ||||
|     { | ||||
|         return __DIR__; | ||||
|     } | ||||
|  | ||||
|     public function getCacheDir() | ||||
|     { | ||||
|         return dirname(__DIR__).'/var/cache/'.$this->getEnvironment(); | ||||
|     } | ||||
|  | ||||
|     public function getLogDir() | ||||
|     { | ||||
|         return dirname(__DIR__).'/var/logs'; | ||||
|     } | ||||
|  | ||||
|     public function registerContainerConfiguration(LoaderInterface $loader) | ||||
|     { | ||||
|         $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml'); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										13
									
								
								app/Resources/views/base.html.twig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/Resources/views/base.html.twig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <title>{% block title %}Welcome!{% endblock %}</title> | ||||
|         {% block stylesheets %}{% endblock %} | ||||
|         <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" /> | ||||
|     </head> | ||||
|     <body> | ||||
|         {% block body %}{% endblock %} | ||||
|         {% block javascripts %}{% endblock %} | ||||
|     </body> | ||||
| </html> | ||||
							
								
								
									
										76
									
								
								app/Resources/views/default/index.html.twig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								app/Resources/views/default/index.html.twig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| {% extends 'base.html.twig' %} | ||||
|  | ||||
| {% block body %} | ||||
|     <div id="wrapper"> | ||||
|         <div id="container"> | ||||
|             <div id="welcome"> | ||||
|                 <h1><span>Welcome to</span> Symfony {{ constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION') }}</h1> | ||||
|             </div> | ||||
|  | ||||
|             <div id="status"> | ||||
|                 <p> | ||||
|                     <svg id="icon-status" width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1671 566q0 40-28 68l-724 724-136 136q-28 28-68 28t-68-28l-136-136-362-362q-28-28-28-68t28-68l136-136q28-28 68-28t68 28l294 295 656-657q28-28 68-28t68 28l136 136q28 28 28 68z" fill="#759E1A"/></svg> | ||||
|  | ||||
|                     Your application is now ready. You can start working on it at: | ||||
|                     <code>{{ base_dir }}</code> | ||||
|                 </p> | ||||
|             </div> | ||||
|  | ||||
|             <div id="next"> | ||||
|                 <h2>What's next?</h2> | ||||
|                 <p> | ||||
|                     <svg id="icon-book" version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="-12.5 9 64 64" enable-background="new -12.5 9 64 64" xml:space="preserve"> | ||||
|                         <path fill="#AAA" d="M6.8,40.8c2.4,0.8,4.5-0.7,4.9-2.5c0.2-1.2-0.3-2.1-1.3-3.2l-0.8-0.8c-0.4-0.5-0.6-1.3-0.2-1.9 | ||||
|                             c0.4-0.5,0.9-0.8,1.8-0.5c1.3,0.4,1.9,1.3,2.9,2.2c-0.4,1.4-0.7,2.9-0.9,4.2l-0.2,1c-0.7,4-1.3,6.2-2.7,7.5 | ||||
|                             c-0.3,0.3-0.7,0.5-1.3,0.6c-0.3,0-0.4-0.3-0.4-0.3c0-0.3,0.2-0.3,0.3-0.4c0.2-0.1,0.5-0.3,0.4-0.8c0-0.7-0.6-1.3-1.3-1.3 | ||||
|                             c-0.6,0-1.4,0.6-1.4,1.7s1,1.9,2.4,1.8c0.8,0,2.5-0.3,4.2-2.5c2-2.5,2.5-5.4,2.9-7.4l0.5-2.8c0.3,0,0.5,0.1,0.8,0.1 | ||||
|                             c2.4,0.1,3.7-1.3,3.7-2.3c0-0.6-0.3-1.2-0.9-1.2c-0.4,0-0.8,0.3-1,0.8c-0.1,0.6,0.8,1.1,0.1,1.5c-0.5,0.3-1.4,0.6-2.7,0.4l0.3-1.3 | ||||
|                             c0.5-2.6,1-5.7,3.2-5.8c0.2,0,0.8,0,0.8,0.4c0,0.2,0,0.2-0.2,0.5c-0.2,0.3-0.3,0.4-0.2,0.7c0,0.7,0.5,1.1,1.2,1.1 | ||||
|                             c0.9,0,1.2-1,1.2-1.4c0-1.2-1.2-1.8-2.6-1.8c-1.5,0.1-2.8,0.9-3.7,2.1c-1.1,1.3-1.8,2.9-2.3,4.5c-0.9-0.8-1.6-1.8-3.1-2.3 | ||||
|                             c-1.1-0.7-2.3-0.5-3.4,0.3c-0.5,0.4-0.8,1-1,1.6c-0.4,1.5,0.4,2.9,0.8,3.4l0.9,1c0.2,0.2,0.6,0.8,0.4,1.5c-0.3,0.8-1.2,1.3-2.1,1 | ||||
|                             c-0.4-0.2-1-0.5-0.9-0.9c0.1-0.2,0.2-0.3,0.3-0.5s0.1-0.3,0.1-0.3c0.2-0.6-0.1-1.4-0.7-1.6c-0.6-0.2-1.2,0-1.3,0.8 | ||||
|                             C4.3,38.4,4.7,40,6.8,40.8z M46.1,20.9c0-4.2-3.2-7.5-7.1-7.5h-3.8C34.8,10.8,32.7,9,30.2,9L-2.3,9.1c-2.8,0.1-4.9,2.4-4.9,5.4 | ||||
|                             L-7,58.6c0,4.8,8.1,13.9,11.6,14.1l34.7-0.1c3.9,0,7-3.4,7-7.6L46.1,20.9z M-0.3,36.4c0-8.6,6.5-15.6,14.5-15.6 | ||||
|                             c8,0,14.5,7,14.5,15.6S22.1,52,14.2,52C6.1,52-0.3,45-0.3,36.4z M42.1,65.1c0,1.8-1.5,3.1-3.1,3.1H4.6c-0.7,0-3-1.8-4.5-4.4h30.4 | ||||
|                             c2.8,0,5-2.4,5-5.4V17.9h3.7c1.6,0,2.9,1.4,2.9,3.1V65.1L42.1,65.1z"/> | ||||
|                     </svg> | ||||
|  | ||||
|                     Read the documentation to learn | ||||
|                     <a href="http://symfony.com/doc/{{ constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION')[:3] }}/book/page_creation.html"> | ||||
|                         How to create your first page in Symfony | ||||
|                     </a> | ||||
|                 </p> | ||||
|             </div> | ||||
|  | ||||
|         </div> | ||||
|     </div> | ||||
| {% endblock %} | ||||
|  | ||||
| {% block stylesheets %} | ||||
| <style> | ||||
|     body { background: #F5F5F5; font: 18px/1.5 sans-serif; } | ||||
|     h1, h2 { line-height: 1.2; margin: 0 0 .5em; } | ||||
|     h1 { font-size: 36px; } | ||||
|     h2 { font-size: 21px; margin-bottom: 1em; } | ||||
|     p { margin: 0 0 1em 0; } | ||||
|     a { color: #0000F0; } | ||||
|     a:hover { text-decoration: none; } | ||||
|     code { background: #F5F5F5; max-width: 100px; padding: 2px 6px; word-wrap: break-word; } | ||||
|     #wrapper { background: #FFF; margin: 1em auto; max-width: 800px; width: 95%; } | ||||
|     #container { padding: 2em; } | ||||
|     #welcome, #status { margin-bottom: 2em; } | ||||
|     #welcome h1 span { display: block; font-size: 75%; } | ||||
|     #icon-status, #icon-book { float: left; height: 64px; margin-right: 1em; margin-top: -4px; width: 64px; } | ||||
|     #icon-book { display: none; } | ||||
|  | ||||
|     @media (min-width: 768px) { | ||||
|         #wrapper { width: 80%; margin: 2em auto; } | ||||
|         #icon-book { display: inline-block; } | ||||
|         #status a, #next a { display: block; } | ||||
|  | ||||
|         @-webkit-keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } } | ||||
|         @keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } } | ||||
|         .sf-toolbar { opacity: 0; -webkit-animation: fade-in 1s .2s forwards; animation: fade-in 1s .2s forwards;} | ||||
|     } | ||||
| </style> | ||||
| {% endblock %} | ||||
							
								
								
									
										11
									
								
								app/autoload.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/autoload.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?php | ||||
|  | ||||
| use Doctrine\Common\Annotations\AnnotationRegistry; | ||||
| use Composer\Autoload\ClassLoader; | ||||
|  | ||||
| /** @var ClassLoader $loader */ | ||||
| $loader = require __DIR__.'/../vendor/autoload.php'; | ||||
|  | ||||
| AnnotationRegistry::registerLoader([$loader, 'loadClass']); | ||||
|  | ||||
| return $loader; | ||||
							
								
								
									
										68
									
								
								app/config/config.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								app/config/config.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| imports: | ||||
|     - { resource: parameters.yml } | ||||
|     - { resource: security.yml } | ||||
|     - { resource: services.yml } | ||||
|  | ||||
| # Put parameters here that don't need to change on each machine where the app is deployed | ||||
| # http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration | ||||
| parameters: | ||||
|     locale: en | ||||
|  | ||||
| framework: | ||||
|     #esi:             ~ | ||||
|     #translator:      { fallbacks: ["%locale%"] } | ||||
|     secret:          "%secret%" | ||||
|     router: | ||||
|         resource: "%kernel.root_dir%/config/routing.yml" | ||||
|         strict_requirements: ~ | ||||
|     form:            ~ | ||||
|     csrf_protection: ~ | ||||
|     validation:      { enable_annotations: true } | ||||
|     #serializer:      { enable_annotations: true } | ||||
|     templating: | ||||
|         engines: ['twig'] | ||||
|     default_locale:  "%locale%" | ||||
|     trusted_hosts:   ~ | ||||
|     trusted_proxies: ~ | ||||
|     session: | ||||
|         # http://symfony.com/doc/current/reference/configuration/framework.html#handler-id | ||||
|         handler_id:  session.handler.native_file | ||||
|         save_path:   "%kernel.root_dir%/../var/sessions/%kernel.environment%" | ||||
|     fragments:       ~ | ||||
|     http_method_override: true | ||||
|     assets: ~ | ||||
|  | ||||
| # Twig Configuration | ||||
| twig: | ||||
|     debug:            "%kernel.debug%" | ||||
|     strict_variables: "%kernel.debug%" | ||||
|  | ||||
| # Doctrine Configuration | ||||
| doctrine: | ||||
|     dbal: | ||||
|         driver:   pdo_mysql | ||||
|         host:     "%database_host%" | ||||
|         port:     "%database_port%" | ||||
|         dbname:   "%database_name%" | ||||
|         user:     "%database_user%" | ||||
|         password: "%database_password%" | ||||
|         charset:  UTF8 | ||||
|         # if using pdo_sqlite as your database driver: | ||||
|         #   1. add the path in parameters.yml | ||||
|         #     e.g. database_path: "%kernel.root_dir%/data/data.db3" | ||||
|         #   2. Uncomment database_path in parameters.yml.dist | ||||
|         #   3. Uncomment next line: | ||||
|         #     path:     "%database_path%" | ||||
|  | ||||
|     orm: | ||||
|         auto_generate_proxy_classes: "%kernel.debug%" | ||||
|         naming_strategy: doctrine.orm.naming_strategy.underscore | ||||
|         auto_mapping: true | ||||
|  | ||||
| # Swiftmailer Configuration | ||||
| swiftmailer: | ||||
|     transport: "%mailer_transport%" | ||||
|     host:      "%mailer_host%" | ||||
|     username:  "%mailer_user%" | ||||
|     password:  "%mailer_password%" | ||||
|     spool:     { type: memory } | ||||
							
								
								
									
										34
									
								
								app/config/config_dev.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								app/config/config_dev.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| imports: | ||||
|     - { resource: config.yml } | ||||
|  | ||||
| framework: | ||||
|     router: | ||||
|         resource: "%kernel.root_dir%/config/routing_dev.yml" | ||||
|         strict_requirements: true | ||||
|     profiler: { only_exceptions: false } | ||||
|  | ||||
| web_profiler: | ||||
|     toolbar: true | ||||
|     intercept_redirects: false | ||||
|  | ||||
| monolog: | ||||
|     handlers: | ||||
|         main: | ||||
|             type: stream | ||||
|             path: "%kernel.logs_dir%/%kernel.environment%.log" | ||||
|             level: debug | ||||
|             channels: [!event] | ||||
|         console: | ||||
|             type:   console | ||||
|             channels: [!event, !doctrine] | ||||
|         # uncomment to get logging in your browser | ||||
|         # you may have to allow bigger header sizes in your Web server configuration | ||||
|         #firephp: | ||||
|         #    type:   firephp | ||||
|         #    level:  info | ||||
|         #chromephp: | ||||
|         #    type:   chromephp | ||||
|         #    level:  info | ||||
|  | ||||
| #swiftmailer: | ||||
| #    delivery_address: me@example.com | ||||
							
								
								
									
										21
									
								
								app/config/config_prod.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/config/config_prod.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| imports: | ||||
|     - { resource: config.yml } | ||||
|  | ||||
| #doctrine: | ||||
| #    orm: | ||||
| #        metadata_cache_driver: apc | ||||
| #        result_cache_driver: apc | ||||
| #        query_cache_driver: apc | ||||
|  | ||||
| monolog: | ||||
|     handlers: | ||||
|         main: | ||||
|             type:         fingers_crossed | ||||
|             action_level: error | ||||
|             handler:      nested | ||||
|         nested: | ||||
|             type:  stream | ||||
|             path:  "%kernel.logs_dir%/%kernel.environment%.log" | ||||
|             level: debug | ||||
|         console: | ||||
|             type:  console | ||||
							
								
								
									
										16
									
								
								app/config/config_test.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/config/config_test.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| imports: | ||||
|     - { resource: config_dev.yml } | ||||
|  | ||||
| framework: | ||||
|     test: ~ | ||||
|     session: | ||||
|         storage_id: session.storage.mock_file | ||||
|     profiler: | ||||
|         collect: false | ||||
|  | ||||
| web_profiler: | ||||
|     toolbar: false | ||||
|     intercept_redirects: false | ||||
|  | ||||
| swiftmailer: | ||||
|     disable_delivery: true | ||||
							
								
								
									
										19
									
								
								app/config/parameters.yml.dist
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/config/parameters.yml.dist
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # This file is a "template" of what your parameters.yml file should look like | ||||
| # Set parameters here that may be different on each deployment target of the app, e.g. development, staging, production. | ||||
| # http://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration | ||||
| parameters: | ||||
|     database_host:     127.0.0.1 | ||||
|     database_port:     ~ | ||||
|     database_name:     symfony | ||||
|     database_user:     root | ||||
|     database_password: ~ | ||||
|     # You should uncomment this if you want use pdo_sqlite | ||||
|     # database_path: "%kernel.root_dir%/data.db3" | ||||
|  | ||||
|     mailer_transport:  smtp | ||||
|     mailer_host:       127.0.0.1 | ||||
|     mailer_user:       ~ | ||||
|     mailer_password:   ~ | ||||
|  | ||||
|     # A secret key that's used to generate certain security-related tokens | ||||
|     secret:            ThisTokenIsNotSoSecretChangeIt | ||||
							
								
								
									
										3
									
								
								app/config/routing.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/config/routing.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| app: | ||||
|     resource: "@AppBundle/Controller/" | ||||
|     type:     annotation | ||||
							
								
								
									
										14
									
								
								app/config/routing_dev.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/config/routing_dev.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| _wdt: | ||||
|     resource: "@WebProfilerBundle/Resources/config/routing/wdt.xml" | ||||
|     prefix:   /_wdt | ||||
|  | ||||
| _profiler: | ||||
|     resource: "@WebProfilerBundle/Resources/config/routing/profiler.xml" | ||||
|     prefix:   /_profiler | ||||
|  | ||||
| _errors: | ||||
|     resource: "@TwigBundle/Resources/config/routing/errors.xml" | ||||
|     prefix:   /_error | ||||
|  | ||||
| _main: | ||||
|     resource: routing.yml | ||||
							
								
								
									
										24
									
								
								app/config/security.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								app/config/security.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| # To get started with security, check out the documentation: | ||||
| # http://symfony.com/doc/current/book/security.html | ||||
| security: | ||||
|  | ||||
|     # http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers | ||||
|     providers: | ||||
|         in_memory: | ||||
|             memory: ~ | ||||
|  | ||||
|     firewalls: | ||||
|         # disables authentication for assets and the profiler, adapt it according to your needs | ||||
|         dev: | ||||
|             pattern: ^/(_(profiler|wdt)|css|images|js)/ | ||||
|             security: false | ||||
|  | ||||
|         main: | ||||
|             anonymous: ~ | ||||
|             # activate different ways to authenticate | ||||
|  | ||||
|             # http_basic: ~ | ||||
|             # http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate | ||||
|  | ||||
|             # form_login: ~ | ||||
|             # http://symfony.com/doc/current/cookbook/security/form_login_setup.html | ||||
							
								
								
									
										17
									
								
								app/config/services.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/config/services.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| # Learn more about services, parameters and containers at | ||||
| # http://symfony.com/doc/current/book/service_container.html | ||||
| parameters: | ||||
| #    parameter_name: value | ||||
|  | ||||
| services: | ||||
|  | ||||
|     app.eloquent: | ||||
|         class: AppBundle\Eloquent | ||||
|         arguments: [] | ||||
|  | ||||
|     # app.fine_diff: | ||||
|     #     class: AppBundle\FineDiff | ||||
|     #     arguments: [] | ||||
|  | ||||
|     twig.exception_listener: | ||||
|       class: stdObject | ||||
							
								
								
									
										27
									
								
								bin/console
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								bin/console
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| use Symfony\Bundle\FrameworkBundle\Console\Application; | ||||
| use Symfony\Component\Console\Input\ArgvInput; | ||||
| use Symfony\Component\Debug\Debug; | ||||
|  | ||||
| // if you don't want to setup permissions the proper way, just uncomment the following PHP line | ||||
| // read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information | ||||
| //umask(0000); | ||||
|  | ||||
| set_time_limit(0); | ||||
|  | ||||
| /** @var Composer\Autoload\ClassLoader $loader */ | ||||
| $loader = require __DIR__.'/../app/autoload.php'; | ||||
|  | ||||
| $input = new ArgvInput(); | ||||
| $env = $input->getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev'); | ||||
| $debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod'; | ||||
|  | ||||
| if ($debug) { | ||||
|     Debug::enable(); | ||||
| } | ||||
|  | ||||
| $kernel = new AppKernel($env, $debug); | ||||
| $application = new Application($kernel); | ||||
| $application->run($input); | ||||
							
								
								
									
										146
									
								
								bin/symfony_requirements
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										146
									
								
								bin/symfony_requirements
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| require_once dirname(__FILE__).'/../var/SymfonyRequirements.php'; | ||||
|  | ||||
| $lineSize = 70; | ||||
| $symfonyRequirements = new SymfonyRequirements(); | ||||
| $iniPath = $symfonyRequirements->getPhpIniConfigPath(); | ||||
|  | ||||
| echo_title('Symfony Requirements Checker'); | ||||
|  | ||||
| echo '> PHP is using the following php.ini file:'.PHP_EOL; | ||||
| if ($iniPath) { | ||||
|     echo_style('green', '  '.$iniPath); | ||||
| } else { | ||||
|     echo_style('yellow', '  WARNING: No configuration file (php.ini) used by PHP!'); | ||||
| } | ||||
|  | ||||
| echo PHP_EOL.PHP_EOL; | ||||
|  | ||||
| echo '> Checking Symfony requirements:'.PHP_EOL.'  '; | ||||
|  | ||||
| $messages = array(); | ||||
| foreach ($symfonyRequirements->getRequirements() as $req) { | ||||
|     if ($helpText = get_error_message($req, $lineSize)) { | ||||
|         echo_style('red', 'E'); | ||||
|         $messages['error'][] = $helpText; | ||||
|     } else { | ||||
|         echo_style('green', '.'); | ||||
|     } | ||||
| } | ||||
|  | ||||
| $checkPassed = empty($messages['error']); | ||||
|  | ||||
| foreach ($symfonyRequirements->getRecommendations() as $req) { | ||||
|     if ($helpText = get_error_message($req, $lineSize)) { | ||||
|         echo_style('yellow', 'W'); | ||||
|         $messages['warning'][] = $helpText; | ||||
|     } else { | ||||
|         echo_style('green', '.'); | ||||
|     } | ||||
| } | ||||
|  | ||||
| if ($checkPassed) { | ||||
|     echo_block('success', 'OK', 'Your system is ready to run Symfony projects'); | ||||
| } else { | ||||
|     echo_block('error', 'ERROR', 'Your system is not ready to run Symfony projects'); | ||||
|  | ||||
|     echo_title('Fix the following mandatory requirements', 'red'); | ||||
|  | ||||
|     foreach ($messages['error'] as $helpText) { | ||||
|         echo ' * '.$helpText.PHP_EOL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| if (!empty($messages['warning'])) { | ||||
|     echo_title('Optional recommendations to improve your setup', 'yellow'); | ||||
|  | ||||
|     foreach ($messages['warning'] as $helpText) { | ||||
|         echo ' * '.$helpText.PHP_EOL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| echo PHP_EOL; | ||||
| echo_style('title', 'Note'); | ||||
| echo '  The command console could use a different php.ini file'.PHP_EOL; | ||||
| echo_style('title', '~~~~'); | ||||
| echo '  than the one used with your web server. To be on the'.PHP_EOL; | ||||
| echo '      safe side, please check the requirements from your web'.PHP_EOL; | ||||
| echo '      server using the '; | ||||
| echo_style('yellow', 'web/config.php'); | ||||
| echo ' script.'.PHP_EOL; | ||||
| echo PHP_EOL; | ||||
|  | ||||
| exit($checkPassed ? 0 : 1); | ||||
|  | ||||
| function get_error_message(Requirement $requirement, $lineSize) | ||||
| { | ||||
|     if ($requirement->isFulfilled()) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     $errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL.'   ').PHP_EOL; | ||||
|     $errorMessage .= '   > '.wordwrap($requirement->getHelpText(), $lineSize - 5, PHP_EOL.'   > ').PHP_EOL; | ||||
|  | ||||
|     return $errorMessage; | ||||
| } | ||||
|  | ||||
| function echo_title($title, $style = null) | ||||
| { | ||||
|     $style = $style ?: 'title'; | ||||
|  | ||||
|     echo PHP_EOL; | ||||
|     echo_style($style, $title.PHP_EOL); | ||||
|     echo_style($style, str_repeat('~', strlen($title)).PHP_EOL); | ||||
|     echo PHP_EOL; | ||||
| } | ||||
|  | ||||
| function echo_style($style, $message) | ||||
| { | ||||
|     // ANSI color codes | ||||
|     $styles = array( | ||||
|         'reset' => "\033[0m", | ||||
|         'red' => "\033[31m", | ||||
|         'green' => "\033[32m", | ||||
|         'yellow' => "\033[33m", | ||||
|         'error' => "\033[37;41m", | ||||
|         'success' => "\033[37;42m", | ||||
|         'title' => "\033[34m", | ||||
|     ); | ||||
|     $supports = has_color_support(); | ||||
|  | ||||
|     echo($supports ? $styles[$style] : '').$message.($supports ? $styles['reset'] : ''); | ||||
| } | ||||
|  | ||||
| function echo_block($style, $title, $message) | ||||
| { | ||||
|     $message = ' '.trim($message).' '; | ||||
|     $width = strlen($message); | ||||
|  | ||||
|     echo PHP_EOL.PHP_EOL; | ||||
|  | ||||
|     echo_style($style, str_repeat(' ', $width)); | ||||
|     echo PHP_EOL; | ||||
|     echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT)); | ||||
|     echo PHP_EOL; | ||||
|     echo_style($style, $message); | ||||
|     echo PHP_EOL; | ||||
|     echo_style($style, str_repeat(' ', $width)); | ||||
|     echo PHP_EOL; | ||||
| } | ||||
|  | ||||
| function has_color_support() | ||||
| { | ||||
|     static $support; | ||||
|  | ||||
|     if (null === $support) { | ||||
|         if (DIRECTORY_SEPARATOR == '\\') { | ||||
|             $support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI'); | ||||
|         } else { | ||||
|             $support = function_exists('posix_isatty') && @posix_isatty(STDOUT); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return $support; | ||||
| } | ||||
							
								
								
									
										1
									
								
								cli-client/.config1/config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								cli-client/.config1/config.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| {"last_sync_id":81,"file_map":[],"test":"abcd","client_id":"11111111111111111111111111111111","last_sync_time":1476289357,"session_id":null,"folder_items":[]} | ||||
							
								
								
									
										1
									
								
								cli-client/.config2/config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								cli-client/.config2/config.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| {"last_sync_id":80,"file_map":[],"client_id":"22222222222222222222222222222222","last_sync_time":1476289618,"folder_items":[],"session_id":null} | ||||
							
								
								
									
										2
									
								
								cli-client/client1.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								cli-client/client1.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| #!/bin/bash | ||||
| php main.php --config ~/src/notes/cli-client/.config1 "$@" | ||||
							
								
								
									
										2
									
								
								cli-client/client2.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								cli-client/client2.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| #!/bin/bash | ||||
| php main.php --config ~/src/notes/cli-client/.config2 "$@" | ||||
							
								
								
									
										174
									
								
								cli-client/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								cli-client/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	//"bufio" | ||||
| 	//"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	// "os/exec" | ||||
| 	// "os/user" | ||||
| 	"path/filepath" | ||||
| 	"path" | ||||
| 	"crypto/md5" | ||||
| 	// "runtime" | ||||
| 	// "strconv" | ||||
| 	"strings" | ||||
| 	// "time" | ||||
| 	"net/url" | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/jessevdk/go-flags" | ||||
| ) | ||||
|  | ||||
| const VERSION = "1.0.0" | ||||
|  | ||||
| type SyncCommandOptions struct { | ||||
| 	// FfmpegPath        string `long:"ffmpeg" description:"Path to ffmpeg." default:"ffmpeg"` | ||||
| 	// FrameDirPath      string `short:"d" long:"frame-dir" description:"Path to directory that will contain the captured frames. (default: <PictureDirectory>/pmcctv)"` | ||||
| 	// RemoteDir         string `short:"r" long:"remote-dir" description:"Remote location where frames will be saved to. Must contain a path compatible with scp (eg. user@someip:~/pmcctv)."` | ||||
| 	// RemotePort        string `short:"p" long:"remote-port" description:"Port of remote location where frames will be saved to. If not set, whatever is the default scp port will be used (should be 22)."` | ||||
| 	// BurstModeDuration int    `short:"b" long:"burst-mode-duration" description:"Duration of burst mode, in seconds. Set to 0 to disable burst mode altogether." default:"10"` | ||||
| 	// BurstModeFormat   string `short:"f" long:"burst-mode-format" description:"Format of burst mode captured files, either \"image\" or \"video\"." default:"video"` | ||||
| 	// FramesTtl         int    `short:"t" long:"time-to-live" description:"For how long captured frames should be kept, in days." default:"7"` | ||||
| 	// InputDevice       string `short:"i" long:"input-device" description:"Name of capture input device. (default: auto-detect)"` | ||||
| } | ||||
|  | ||||
| type AppCommandOptions struct { | ||||
| 	Version bool `long:"version" description:"Display version information"` | ||||
| } | ||||
|  | ||||
| type CommandOptions struct { | ||||
| 	App AppCommandOptions | ||||
| 	Sync SyncCommandOptions | ||||
| } | ||||
|  | ||||
| func printHelp(flagParser *flags.Parser) { | ||||
| 	flagParser.WriteHelp(os.Stdout) | ||||
| 	fmt.Printf("\n") | ||||
| 	fmt.Printf("For help with a particular command, type \"%s <command> --help\"\n", path.Base(os.Args[0]))	 | ||||
| } | ||||
|  | ||||
| func createFlagParser() (CommandOptions, *flags.Parser) { | ||||
| 	var opts CommandOptions | ||||
| 	flagParser := flags.NewParser(&opts.App, flags.HelpFlag|flags.PassDoubleDash) | ||||
|  | ||||
| 	flagParser.AddCommand( | ||||
| 		"sync", | ||||
| 		"Synchronize notes", | ||||
| 		"Synchronize local notes with the server.", | ||||
| 		&opts.Sync, | ||||
| 	) | ||||
|  | ||||
| 	return opts, flagParser | ||||
| } | ||||
|  | ||||
| func createId(path string) string { | ||||
| 	h := md5.New() | ||||
| 	io.WriteString(h, "31208854954776365651") | ||||
| 	io.WriteString(h, path) | ||||
| 	return fmt.Sprintf("%x", h.Sum(nil)) | ||||
| } | ||||
|  | ||||
| func readFile(path string) (string, error) { | ||||
| 	content, err := ioutil.ReadFile(path) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return string(content), nil | ||||
| } | ||||
|  | ||||
| func makeApiCall(method string, path string, data url.Values) (error, []byte) { | ||||
| 	baseUrl := "http://127.0.0.1:8000" | ||||
| 	fullUrl := baseUrl + "/" + path | ||||
|  | ||||
| 	client := http.Client{} | ||||
| 	request, err := http.NewRequest(method, fullUrl, strings.NewReader(data.Encode())) | ||||
| 	if err != nil { | ||||
| 		return err, []byte{} | ||||
| 	} | ||||
|  | ||||
| 	request.Header.Add("Content-Type", "application/x-www-form-urlencoded") | ||||
|  | ||||
| 	response, err := client.Do(request) | ||||
| 	body, err := ioutil.ReadAll(response.Body) | ||||
| 	if err != nil { | ||||
| 		return err, []byte{} | ||||
| 	} | ||||
|  | ||||
| 	return nil, body | ||||
| } | ||||
|  | ||||
| // type Note struct { | ||||
| //     Id string | ||||
| //     Title string | ||||
| //     Body string | ||||
| // } | ||||
|  | ||||
| func main() { | ||||
| 	var err error | ||||
|  | ||||
| 	//err, body := makeApiCall("GET", "users/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", url.Values{}) | ||||
|  | ||||
| 	note := url.Values{} | ||||
| 	note.Add("title", "from go") | ||||
| 	note.Add("body", "body from go") | ||||
|  | ||||
| 	err, body := makeApiCall("POST", "notes", note) | ||||
| 	fmt.Println(err) | ||||
| 	fmt.Println(string(body)) | ||||
| 	os.Exit(0) | ||||
|  | ||||
|  | ||||
|  | ||||
| 	opts, flagParser := createFlagParser() | ||||
|  | ||||
| 	args, err := flagParser.Parse() | ||||
|  | ||||
| 	if err != nil { | ||||
| 		t := err.(*flags.Error).Type | ||||
| 		if t == flags.ErrHelp { | ||||
| 			printHelp(flagParser) | ||||
| 			os.Exit(0) | ||||
| 		} else if t == flags.ErrCommandRequired { | ||||
| 			// Here handle default flags (which are not associated with any command) | ||||
| 			if opts.App.Version { | ||||
| 				fmt.Println(VERSION) | ||||
| 				os.Exit(0) | ||||
| 			} | ||||
| 			printHelp(flagParser) | ||||
| 			os.Exit(0) | ||||
| 		} else { | ||||
| 			fmt.Printf("Error: %s\n", err) | ||||
| 			fmt.Printf("Type '%s --help' for more information.\n", path.Base(os.Args[0])) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	_ = args | ||||
|  | ||||
| 	fullPath := "/home/laurent/src/notes/cli-client/test" | ||||
|  | ||||
| 	walkPath := func (path string, info os.FileInfo, err error) error { | ||||
| 		if len(path) - len(fullPath) <= 0 { | ||||
| 			return nil | ||||
| 		} | ||||
| 		p := path[len(fullPath)+1:]; | ||||
| 		fmt.Println(p) | ||||
| 		fmt.Println(createId(p)) | ||||
|  | ||||
| 		if !info.IsDir() { | ||||
| 			content, err := readFile(path) | ||||
| 			if err != nil { | ||||
| 				fmt.Println(err) | ||||
| 				return err | ||||
| 			} | ||||
| 			fmt.Println(content) | ||||
| 		} | ||||
|  | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	filepath.Walk(fullPath, walkPath) | ||||
| } | ||||
							
								
								
									
										349
									
								
								cli-client/main.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										349
									
								
								cli-client/main.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,349 @@ | ||||
| <?php | ||||
|  | ||||
| function escapePathElement($element) { | ||||
| 	$valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ÀàÁáÂâÃãÄäÇçÈèÉéÊêËëÌìÍíÎîÏïÑnÒòÓóÔôÕõÖöŠšÚùÛúÜûÙüÝyŸÿŽz_- ().,'; | ||||
| 	$output = ''; | ||||
| 	$chars = preg_split('//u', $element, -1, PREG_SPLIT_NO_EMPTY); // Split a UTF-8 string into characters | ||||
| 	foreach ($chars as $c) { | ||||
| 		if (strpos($valid, $c) !== false) { | ||||
| 			$output .= $c; | ||||
| 		} else { | ||||
| 			$output .= rawurlencode($c); | ||||
| 		} | ||||
| 	} | ||||
| 	return $output; | ||||
| } | ||||
|  | ||||
| function escapePath($path) { | ||||
| 	$output = ''; | ||||
| 	$elements = preg_split('/[\\\\\/]/', $path); | ||||
| 	for ($i = 0; $i < count($elements); $i++) { | ||||
| 		$e = $elements[$i]; | ||||
| 		if ($i > 0) $output .= '/'; | ||||
| 		$output .= escapePathElement($e); | ||||
| 	} | ||||
| 	return $output; | ||||
| } | ||||
|  | ||||
| class Api { | ||||
|  | ||||
| 	private $sessionId = null; | ||||
| 	private $baseUrl = null; | ||||
|  | ||||
| 	public function __construct($baseUrl) { | ||||
| 		$this->baseUrl = $baseUrl; | ||||
| 	} | ||||
|  | ||||
| 	static public function createId($string) { | ||||
| 		// TODO: This needs to be unique per user | ||||
| 		return md5('gKcr0 ^L3UL^fJV%1IW~~/Q`.,WRAr</8@$.k|uyK-w^d:k|{h!%(};|)OY9^lu=' . $string); | ||||
| 	} | ||||
|  | ||||
| 	public function setSessionId($sessionId) { | ||||
| 		$this->sessionId = $sessionId; | ||||
| 	} | ||||
|  | ||||
| 	public function toCurlCmd($method, $url, $data = null) { | ||||
| 		$cmd = 'curl'; | ||||
|  | ||||
| 		$addMethod = true; | ||||
| 		if ($method == 'GET') $addMethod = false; | ||||
| 		if ($method == 'POST' && count($data)) $addMethod = false; | ||||
| 		if ($addMethod) $cmd .= ' -X ' . $method; | ||||
|  | ||||
| 		if ($data) { | ||||
| 			foreach ($data as $k => $v) { | ||||
| 				$cmd .= ' -F "' . $k . '=' . rawurlencode($v) . '"'; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		$cmd .= ' ' . "'" . $url . "'"; | ||||
| 		return $cmd; | ||||
| 	} | ||||
|  | ||||
| 	public function exec($method, $path, $query = null, $data = null) { | ||||
| 		$url = $this->baseUrl . '/' . $path; | ||||
|  | ||||
| 		if (!$query) $query = array(); | ||||
| 		if ($this->sessionId) $query['session'] = $this->sessionId; | ||||
| 		if (count($query)) $url .= '?' . http_build_query($query); | ||||
|  | ||||
| 		$ch = curl_init($url); | ||||
| 		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | ||||
| 		if ($data) curl_setopt($ch, CURLOPT_POSTFIELDS, $data); | ||||
| 		if ($method == 'PATCH' || $method == 'PUT' || $method == 'DELETE') { | ||||
| 			curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); | ||||
| 		} | ||||
|  | ||||
| 		$cmd = $this->toCurlCmd($method, $url, $data); | ||||
| 		echo $cmd . "\n"; | ||||
|  | ||||
| 		$content = curl_exec($ch); | ||||
| 		curl_close($ch); | ||||
|  | ||||
| 		$output = json_decode($content, true); | ||||
| 		if ($output === null) throw new Exception('Invalid response: ' . $content . "\n\nCommand: " . $cmd . "\n"); | ||||
| 		if (isset($output['error'])) throw new Exception('API error: ' . $content . "\n\nCommand: " . $cmd . "\n"); | ||||
|  | ||||
| 		return $output; | ||||
| 	} | ||||
|  | ||||
| 	public function login($email, $password, $clientId) { | ||||
| 		$method = 'POST'; | ||||
| 		$path = 'sessions'; | ||||
| 		$data = array( | ||||
| 			'email' => $email, | ||||
| 			'password' => $password, | ||||
| 			'client_id' => $clientId, | ||||
| 		); | ||||
|  | ||||
| 		return $this->exec($method, $path, null, $data); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| class Config { | ||||
|  | ||||
| 	protected $dirPath = null; | ||||
|  | ||||
| 	public function __construct($dirPath) { | ||||
| 		$this->dirPath = $dirPath; | ||||
| 	} | ||||
|  | ||||
| 	protected function load() { | ||||
| 		$c = @file_get_contents($this->dirPath . '/config.json'); | ||||
| 		$c = json_decode($c, true); | ||||
| 		if ($c === null) $c = array(); | ||||
| 		if (!isset($c['last_sync_id'])) $c['last_sync_id'] = 0; | ||||
| 		if (!isset($c['last_sync_time'])) $c['last_sync_time'] = 0; | ||||
| 		if (!isset($c['folder_items'])) $c['folder_items'] = array(); | ||||
| 		if (!isset($c['client_id'])) $c['client_id'] = null; | ||||
| 		if (!isset($c['session_id'])) $c['session_id'] = null; | ||||
| 		return $c; | ||||
| 	} | ||||
|  | ||||
| 	protected function save($c) { | ||||
| 		file_put_contents($this->dirPath . '/config.json', json_encode($c)); | ||||
| 	} | ||||
|  | ||||
| 	public function get($name) { | ||||
| 		$c = $this->load(); | ||||
| 		if (!isset($c[$name])) throw new Exception('Invalid key name: ' . $name); | ||||
| 		return $c[$name]; | ||||
| 	} | ||||
|  | ||||
| 	public function set($name, $value) { | ||||
| 		$c = $this->load(); | ||||
| 		$c[$name] = $value; | ||||
| 		$this->save($c); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| class FolderItem { | ||||
|  | ||||
| 	private $title = ''; | ||||
| 	private $body = ''; | ||||
| 	private $id; | ||||
| 	private $parentId; | ||||
| 	private $isFolder; | ||||
| 	private $modTime; | ||||
|  | ||||
| 	public function setTitle($v) { $this->title = $v; } | ||||
| 	public function setBody($v) { $this->body = $v; } | ||||
| 	public function setId($v) { $this->id = $v; } | ||||
| 	public function setParentId($v) { $this->parentId = $v; } | ||||
| 	public function setIsFolder($v) { $this->isFolder = $v; } | ||||
| 	public function setModTime($v) { $this->modTime = $v; } | ||||
|  | ||||
| 	public function title() { return $this->title; } | ||||
| 	public function body() { return $this->body; } | ||||
| 	public function id() { return $this->id; } | ||||
| 	public function parentId() { return $this->parentId; } | ||||
| 	public function isFolder() { return $this->isFolder; } | ||||
| 	public function isNote() { return !$this->isFolder(); } | ||||
| 	public function modTime() { return $this->modTime; } | ||||
|  | ||||
| 	public function toApiArray() { | ||||
| 		$output = array( | ||||
| 			'title' => $this->title(), | ||||
| 			'parent_id' => $this->parentId(), | ||||
| 		); | ||||
| 		if ($this->isNote()) $output['body'] = $this->body(); | ||||
| 		return $output; | ||||
| 	} | ||||
|  | ||||
| 	public function fromApiArray($type, $array) { | ||||
| 		$this->setTitle($array['title']); | ||||
| 		if ($type == 'note') $this->setBody($array['body']); | ||||
| 		$this->setId($array['id']); | ||||
| 		$this->setParentId($array['parent_id']); | ||||
| 		$this->setIsFolder($type == 'folder'); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| class FolderItems { | ||||
|  | ||||
| 	private $items = array(); | ||||
|  | ||||
| 	private function getFolderItems($dir, $parentId, &$output) { | ||||
| 		$paths = glob($dir . '/*'); | ||||
| 		foreach ($paths as $path) { | ||||
| 			$isFolder = is_dir($path); | ||||
| 			$modTime = filemtime($path); | ||||
|  | ||||
| 			$o = new FolderItem(); | ||||
| 			$o->setTitle(basename($path)); | ||||
| 			$o->setId(Api::createId($parentId . '_' . $o->title())); | ||||
| 			$o->setParentId($parentId); | ||||
| 			$o->setIsFolder($isFolder); | ||||
| 			$o->setModTime($modTime); | ||||
|  | ||||
| 			if (!$isFolder) $o->setBody(file_get_contents($path)); | ||||
| 			$output[] = $o; | ||||
| 			if ($isFolder) $this->getFolderItems($path, $o->id(), $output); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public function fromPath($path) { | ||||
| 		$this->items = array(); | ||||
| 		$this->getFolderItems($path, null, $this->items); | ||||
| 	} | ||||
|  | ||||
| 	public function all() { | ||||
| 		return $this->items; | ||||
| 	} | ||||
|  | ||||
| 	public function add($item) { | ||||
| 		$this->items[] = $item; | ||||
| 	} | ||||
|  | ||||
| 	public function setById($id, $item) { | ||||
| 		$found = false; | ||||
| 		for ($i = 0; $i < count($this->items); $i++) { | ||||
| 			$it = $this->items[$i]; | ||||
| 			if ($it->id() == $id) { | ||||
| 				$found = true; | ||||
| 				$this->items[$i] = $item; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (!$found) { | ||||
| 			$this->items[] = $item; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public function byId($id) { | ||||
| 		foreach ($this->all() as $item) { | ||||
| 			if ($item->id() == $id) return $item; | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	public function itemFullPath($item) { | ||||
| 		if (!$item->parentId()) return $item->title(); | ||||
| 		$parent = $this->byId($item->parentId()); | ||||
| 		if (!$parent) throw new Exception('Cannot find parent with ID ' . $item->parentId()); | ||||
| 		return escapePath($this->itemFullPath($parent) . '/' . $item->title()); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| $shortopts = ""; | ||||
| $longopts = array( | ||||
|     "config:", | ||||
|     "sync", | ||||
| ); | ||||
|  | ||||
| $flags = getopt($shortopts, $longopts); | ||||
|  | ||||
| if (!isset($flags['config'])) $flags['config'] = '/home/laurent/src/notes/cli-client/.config'; | ||||
|  | ||||
| $config = new Config($flags['config']); | ||||
|  | ||||
| $dataPath = '/home/laurent/src/notes/cli-client/test_' . $config->get('client_id'); | ||||
|  | ||||
| $api = new Api('http://127.0.0.1:8000'); | ||||
| $session = $api->login('test@example.com', '12345678', $config->get('client_id')); | ||||
| $api->setSessionId($session['id']); | ||||
|  | ||||
| if (array_key_exists('sync', $flags)) { | ||||
| 	$syncStartTime = time(); | ||||
| 	$lastSyncTime = $config->get('last_sync_time'); | ||||
| 	$folderItems = new FolderItems(); | ||||
| 	$folderItems->fromPath($dataPath); | ||||
|  | ||||
| 	// ------------------------------------------------------------------------------------------ | ||||
| 	// Get latest changes from API | ||||
| 	// ------------------------------------------------------------------------------------------ | ||||
|  | ||||
| 	$response = $api->exec('GET', 'synchronizer', array('last_id' => $config->get('last_sync_id'))); | ||||
| 	// $response = $api->exec('GET', 'synchronizer', array('last_id' => 80)); | ||||
|  | ||||
| 	$pathMap = array(); | ||||
| 	$folders = array(); | ||||
| 	$notes = array(); | ||||
| 	$maxId = null; | ||||
| 	foreach ($response['items'] as $item) { | ||||
| 		$folderItem = new FolderItem(); | ||||
|  | ||||
| 		switch ($item['type']) { | ||||
|  | ||||
| 			case 'create': | ||||
| 			case 'update': | ||||
|  | ||||
| 				$resource = $api->exec('GET', $item['item_type'] . 's/' . $item['item_id']); | ||||
| 				$folderItem->fromApiArray($item['item_type'], $resource); | ||||
| 				break; | ||||
|  | ||||
| 			default: | ||||
|  | ||||
| 				throw new Exception('Unsupported action type: ' . $item['type']); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		$folderItems->setById($folderItem->id(), $folderItem); | ||||
|  | ||||
| 		$maxId = max($item['id'], $maxId); | ||||
| 	} | ||||
|  | ||||
| 	foreach ($folderItems->all() as $item) { | ||||
| 		$relativePath = $folderItems->itemFullPath($item); | ||||
| 		$path = $dataPath . '/' . $relativePath; | ||||
|  | ||||
| 		foreach (array('folder', 'note') as $itemType) { | ||||
| 			if ($item->isFolder() && $itemType == 'folder') { | ||||
| 				@mkdir($path, 0755, true); // Ignore "File exists" warning | ||||
| 				if (!is_dir($path)) throw new Exception('Could not create folder at ' . $path); | ||||
| 			} | ||||
|  | ||||
| 			if ($item->isNote() && $itemType == 'note') { | ||||
| 				if ($item->body() !== file_get_contents($path)) { | ||||
| 					file_put_contents($path, $item->body()); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		$pathMap[$item->id()] = $relativePath; | ||||
| 	} | ||||
|  | ||||
| 	// ------------------------------------------------------------------------------------------ | ||||
| 	// Send changed notes and folders to API | ||||
| 	// ------------------------------------------------------------------------------------------ | ||||
|  | ||||
| 	foreach ($folderItems->all() as $item) { | ||||
| 		if ($item->modTime() < $lastSyncTime) continue; | ||||
|  | ||||
| 		if ($item->isFolder()) { | ||||
| 			$api->exec('PUT', 'folders/' . $item->id(), null, $item->toApiArray()); | ||||
| 		} else { | ||||
| 			$api->exec('PUT', 'notes/' . $item->id(), null, $item->toApiArray()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	$config->set('last_sync_time', $syncStartTime); | ||||
| 	$config->set('folder_items', json_encode($pathMap)); | ||||
| 	if ($maxId !== null) $config->set('last_sync_id', $maxId); | ||||
| } | ||||
| @@ -0,0 +1,3 @@ | ||||
| # FOLDER2/note1 | ||||
|  | ||||
| Modified on client 2 | ||||
| @@ -0,0 +1 @@ | ||||
| # NOTE 1 | ||||
| @@ -0,0 +1 @@ | ||||
| # NOTE 2 | ||||
| @@ -0,0 +1 @@ | ||||
| test subnode | ||||
| @@ -0,0 +1,3 @@ | ||||
| # FOLDER2/note1 | ||||
|  | ||||
| Modified on client 2 | ||||
| @@ -0,0 +1 @@ | ||||
| # NOTE 1 | ||||
| @@ -0,0 +1 @@ | ||||
| # NOTE 2 | ||||
| @@ -0,0 +1 @@ | ||||
| test subnode | ||||
							
								
								
									
										66
									
								
								composer.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								composer.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| { | ||||
|     "name": "laurent/notes", | ||||
|     "license": "proprietary", | ||||
|     "type": "project", | ||||
|     "autoload": { | ||||
|         "psr-4": { | ||||
|             "": "src/" | ||||
|         }, | ||||
|         "classmap": [ | ||||
|             "app/AppKernel.php", | ||||
|             "app/AppCache.php" | ||||
|         ] | ||||
|     }, | ||||
|     "autoload-dev": { | ||||
|         "psr-4": { | ||||
|             "Tests\\": "tests/" | ||||
|         } | ||||
|     }, | ||||
|     "require": { | ||||
|         "php": ">=5.5.9", | ||||
|         "symfony/symfony": "3.1.*", | ||||
|         "doctrine/orm": "^2.5", | ||||
|         "doctrine/doctrine-bundle": "^1.6", | ||||
|         "doctrine/doctrine-cache-bundle": "^1.2", | ||||
|         "symfony/swiftmailer-bundle": "^2.3", | ||||
|         "symfony/monolog-bundle": "^2.8", | ||||
|         "symfony/polyfill-apcu": "^1.0", | ||||
|         "sensio/distribution-bundle": "^5.0", | ||||
|         "sensio/framework-extra-bundle": "^3.0.2", | ||||
|         "incenteev/composer-parameter-handler": "^2.0", | ||||
|  | ||||
|         "illuminate/database": "*", | ||||
|         "yetanotherape/diff-match-patch": "*" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "sensio/generator-bundle": "^3.0", | ||||
|         "symfony/phpunit-bridge": "^3.0" | ||||
|     }, | ||||
|     "scripts": { | ||||
|         "symfony-scripts": [ | ||||
|             "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", | ||||
|             "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", | ||||
|             "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", | ||||
|             "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", | ||||
|             "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", | ||||
|             "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget" | ||||
|         ], | ||||
|         "post-install-cmd": [ | ||||
|             "@symfony-scripts" | ||||
|         ], | ||||
|         "post-update-cmd": [ | ||||
|             "@symfony-scripts" | ||||
|         ] | ||||
|     }, | ||||
|     "extra": { | ||||
|         "symfony-app-dir": "app", | ||||
|         "symfony-bin-dir": "bin", | ||||
|         "symfony-var-dir": "var", | ||||
|         "symfony-web-dir": "web", | ||||
|         "symfony-tests-dir": "tests", | ||||
|         "symfony-assets-install": "relative", | ||||
|         "incenteev-parameters": { | ||||
|             "file": "app/config/parameters.yml" | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										2386
									
								
								composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2386
									
								
								composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										11
									
								
								notes.sublime-project
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								notes.sublime-project
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| { | ||||
| 	"folders": | ||||
| 	[ | ||||
| 		{ | ||||
| 			"path": ".", | ||||
| 			"folder_exclude_patterns": [ | ||||
| 				"var" | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
							
								
								
									
										31
									
								
								phpunit.xml.dist
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								phpunit.xml.dist
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
|  | ||||
| <!-- https://phpunit.de/manual/current/en/appendixes.configuration.html --> | ||||
| <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd" | ||||
|          backupGlobals="false" | ||||
|          colors="true" | ||||
|          bootstrap="app/autoload.php" | ||||
| > | ||||
|     <php> | ||||
|         <ini name="error_reporting" value="-1" /> | ||||
|         <server name="KERNEL_DIR" value="app/" /> | ||||
|     </php> | ||||
|  | ||||
|     <testsuites> | ||||
|         <testsuite name="Project Test Suite"> | ||||
|             <directory>tests</directory> | ||||
|         </testsuite> | ||||
|     </testsuites> | ||||
|  | ||||
|     <filter> | ||||
|         <whitelist> | ||||
|             <directory>src</directory> | ||||
|             <exclude> | ||||
|                 <directory>src/*Bundle/Resources</directory> | ||||
|                 <directory>src/*/*Bundle/Resources</directory> | ||||
|                 <directory>src/*/Bundle/*Bundle/Resources</directory> | ||||
|             </exclude> | ||||
|         </whitelist> | ||||
|     </filter> | ||||
| </phpunit> | ||||
							
								
								
									
										2
									
								
								run_tests.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								run_tests.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| #!/bin/bash | ||||
| phpunit --bootstrap vendor/autoload.php tests/Model/ | ||||
							
								
								
									
										7
									
								
								src/.htaccess
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/.htaccess
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| <IfModule mod_authz_core.c> | ||||
|     Require all denied | ||||
| </IfModule> | ||||
| <IfModule !mod_authz_core.c> | ||||
|     Order deny,allow | ||||
|     Deny from all | ||||
| </IfModule> | ||||
							
								
								
									
										9
									
								
								src/AppBundle/AppBundle.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/AppBundle/AppBundle.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle; | ||||
|  | ||||
| use Symfony\Component\HttpKernel\Bundle\Bundle; | ||||
|  | ||||
| class AppBundle extends Bundle | ||||
| { | ||||
| } | ||||
							
								
								
									
										197
									
								
								src/AppBundle/Controller/ApiController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								src/AppBundle/Controller/ApiController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,197 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Controller; | ||||
|  | ||||
| use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||||
| use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| use Symfony\Component\HttpFoundation\JsonResponse; | ||||
| use AppBundle\Model\BaseModel; | ||||
| use AppBundle\Model\Session; | ||||
| use AppBundle\Model\User; | ||||
| use AppBundle\Exception\ForbiddenException; | ||||
| use AppBundle\Exception\UnauthorizedException; | ||||
| use Illuminate\Database\Eloquent\Collection; | ||||
| use AppBundle\Exception\BaseException; | ||||
|  | ||||
| abstract class ApiController extends Controller { | ||||
|  | ||||
| 	protected $db = null; | ||||
| 	protected $session = null; | ||||
| 	protected $user = null; | ||||
|  | ||||
| 	private $useTestUserAndSession = true; | ||||
| 	private $testClientNum = 1; | ||||
|  | ||||
| 	public function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container = null) { | ||||
| 		parent::setContainer($container); | ||||
|  | ||||
| 		set_exception_handler(function($e) { | ||||
| 			if ($e instanceof BaseException) { | ||||
| 				$r = $e->toJsonResponse(); | ||||
| 				$r->send(); | ||||
| 				echo "\n"; | ||||
| 			} else { | ||||
| 				$msg = array(); | ||||
| 				$msg[] = 'Exception: ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine(); | ||||
| 				$msg[] = ''; | ||||
| 				$msg[] = $e->getTraceAsString(); | ||||
| 				echo implode("\n", $msg); | ||||
| 				echo "\n"; | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 		// 1. client 1 : bla bla bla | ||||
| 		// 2. client 2 : bla bla bla fromclient2 | ||||
| 		// 3. client 1 : client1bla bla bla | ||||
|  | ||||
| 		// RESULT: client1bla bla bla | ||||
|  | ||||
| 		// Because diff for 3 is done between 2 and 3 | ||||
| 		// Need to introduce revID so that Change class knows between which versions the diff should be made | ||||
|  | ||||
| 		// HACK: get connection once here so that it's initialized and can  | ||||
| 		// be accessed from models. | ||||
| 		$this->db = $this->get('app.eloquent')->connection(); | ||||
|  | ||||
| 		$s = $this->session(); | ||||
|  | ||||
| 		// TODO: to keep it simple, only respond to logged in users, but in theory some data | ||||
| 		// could be public. | ||||
| 		if (!$s || !$this->user()) throw new UnauthorizedException('A session and user are required'); | ||||
|  | ||||
| 		BaseModel::setClientId($s ? $s->client_id : 0); | ||||
| 	} | ||||
|  | ||||
| 	protected function session() { | ||||
| 		if ($this->useTestUserAndSession) { | ||||
| 			$session = Session::find(Session::unhex('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB')); | ||||
| 			if ($session) $session->delete(); | ||||
| 			$session = new Session(); | ||||
| 			$session->id = Session::unhex('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'); | ||||
| 			$session->owner_id = Session::unhex('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'); | ||||
| 			$session->client_id = Session::unhex($this->testClientNum == 1 ? 'C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1' : 'C2C2C2C2C2C2C2C2C2C2C2C2C2C2C2C2'); | ||||
| 			$session->save(); | ||||
| 			return $session; | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		if ($this->session) return $this->session; | ||||
| 		$request = $this->container->get('request_stack')->getCurrentRequest(); | ||||
| 		$this->session = Session::find(BaseModel::unhex($request->query->get('session'))); | ||||
| 		return $this->session; | ||||
| 	} | ||||
|  | ||||
| 	protected function user() { | ||||
| 		if ($this->useTestUserAndSession) { | ||||
| 			$user = User::find(User::unhex('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')); | ||||
| 			if (!$user) { | ||||
| 				$user = new User(); | ||||
| 				$user->id = User::unhex('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'); | ||||
| 				$user->owner_id = $user->id; | ||||
| 				$user->email = 'test@example.com'; | ||||
| 				$user->password = Session::hashPassword('12345678'); | ||||
| 				$user->save(); | ||||
| 			} | ||||
| 			return $user; | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		if ($this->user) return $this->user; | ||||
| 		$s = $this->session(); | ||||
| 		$this->user = $s ? $s->owner() : null; | ||||
| 		return $this->user; | ||||
| 	} | ||||
|  | ||||
| 	protected function aclCheck($resource) { | ||||
| 		if (!is_array($resource)) $resource = array($resource); | ||||
| 		$user = $this->user(); | ||||
| 		if (!$user) throw new ForbiddenException(); | ||||
| 		foreach ($resource as $r) { | ||||
| 			if (!isset($r->owner_id)) continue; | ||||
| 			if ($r->owner_id != $user->id) throw new ForbiddenException(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static private function serializeResponse($data) { | ||||
| 		$output = $data; | ||||
|  | ||||
| 		if ($output instanceof Collection) $output = $output->all(); | ||||
|  | ||||
| 		if ($output instanceof BaseModel) { | ||||
| 			$output = $output->toPublicArray(); | ||||
| 		} else if (is_array($output)) { | ||||
| 			foreach ($output as $k => $v) { | ||||
| 				$output[$k] = self::serializeResponse($v); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return $output; | ||||
| 	} | ||||
|  | ||||
| 	static protected function successResponse($data = null) { | ||||
| 		$output = self::serializeResponse($data); | ||||
| 		return new JsonResponse($output); | ||||
| 	} | ||||
|  | ||||
| 	static protected function errorResponse($message, $errorCode = 0, $httpCode = 400) { | ||||
| 		$o = array('error' => $message, 'code' => $errorCode); | ||||
| 		$response = new JsonResponse($o); | ||||
| 		$response->setStatusCode($httpCode); | ||||
| 		return $response; | ||||
| 	} | ||||
|  | ||||
| 	protected function multipleValues($v) { | ||||
| 		if ($v === null || $v === false) return array(); | ||||
| 		if (strpos((string)$v, ';') === false) return array($v); | ||||
| 		return explode(';', $v); | ||||
| 	} | ||||
|  | ||||
| 	// PHP doesn't parse PATCH and PUT requests automatically, so it needs | ||||
| 	// to be done manually. | ||||
| 	// http://stackoverflow.com/a/5488449/561309 | ||||
| 	protected function patchParameters() { | ||||
| 		$output = array(); | ||||
| 		$input = file_get_contents('php://input'); | ||||
| 		preg_match('/boundary=(.*)$/', $_SERVER['CONTENT_TYPE'], $matches); | ||||
| 		$boundary = $matches[1]; | ||||
| 		$blocks = preg_split("/-+$boundary/", $input); | ||||
| 		array_pop($blocks); | ||||
| 		foreach ($blocks as $id => $block) { | ||||
| 			if (empty($block)) continue; | ||||
|  | ||||
| 			// you'll have to var_dump $block to understand this and maybe replace \n or \r with a visibile char | ||||
|  | ||||
| 			// parse uploaded files | ||||
| 			if (strpos($block, 'application/octet-stream') !== FALSE) { | ||||
| 				// match "name", then everything after "stream" (optional) except for prepending newlines  | ||||
| 				preg_match("/name=\"([^\"]*)\".*stream[\n|\r]+([^\n\r].*)?$/s", $block, $matches); | ||||
| 			} else { | ||||
| 				// match "name" and optional value in between newline sequences | ||||
| 				preg_match('/name=\"([^\"]*)\"[\n|\r]+([^\n\r].*)?\r$/s', $block, $matches); | ||||
| 			} | ||||
| 			if (!isset($matches[2])) { | ||||
| 				// Regex above will not find anything if the parameter has not value. For example | ||||
| 				// "parent_id" below: | ||||
|  | ||||
| 				// Content-Disposition: form-data; name="parent_id" | ||||
| 				// | ||||
| 				// | ||||
| 				// Content-Disposition: form-data; name="id" | ||||
| 				// | ||||
| 				// 54ad197be333c98778c7d6f49506efcb | ||||
|  | ||||
| 				$output[$matches[1]] = ''; | ||||
| 			} else { | ||||
| 				$output[$matches[1]] = $matches[2]; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return $output; | ||||
| 	} | ||||
|  | ||||
| 	protected function putParameters() { | ||||
| 		return $this->patchParameters(); | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										81
									
								
								src/AppBundle/Controller/FoldersController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/AppBundle/Controller/FoldersController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Controller; | ||||
|  | ||||
| use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||||
| use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| use AppBundle\Controller\ApiController; | ||||
| use AppBundle\Model\Folder; | ||||
|  | ||||
| class FoldersController extends ApiController { | ||||
|  | ||||
| 	/** | ||||
| 	 * @Route("/folders") | ||||
| 	 */ | ||||
| 	public function allAction(Request $request) { | ||||
| 		if ($request->isMethod('POST')) { | ||||
| 			$folder = new Folder(); | ||||
| 			$folder->fromPublicArray($request->request->all()); | ||||
| 			$folder->save(); | ||||
| 			return static::successResponse($folder); | ||||
| 		} | ||||
|  | ||||
| 		return static::errorResponse('Invalid method'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @Route("/folders/{id}") | ||||
| 	 */ | ||||
| 	public function oneAction($id, Request $request) { | ||||
| 		$folder = Folder::find(Folder::unhex($id)); | ||||
| 		if (!$folder && !$request->isMethod('PUT')) return static::errorResponse('Not found', 0, 404); | ||||
|  | ||||
| 		if ($request->isMethod('GET')) { | ||||
| 			return static::successResponse($folder); | ||||
| 		} | ||||
|  | ||||
| 		if ($request->isMethod('PUT')) { | ||||
| 			// TODO: call fromPublicArray() - handles unhex conversion | ||||
|  | ||||
| 			$data = $this->putParameters(); | ||||
| 			$isNew = !$folder; | ||||
| 			if ($isNew) $folder = new Folder(); | ||||
| 			foreach ($data as $n => $v) { | ||||
| 				if ($n == 'parent_id') $v = Folder::unhex($v); | ||||
| 				$folder->{$n} = $v; | ||||
| 			} | ||||
| 			$folder->owner_id = $this->user()->id; | ||||
| 			$folder->id = Folder::unhex($id); | ||||
| 			$folder->setIsNew($isNew); | ||||
| 			$folder->save(); | ||||
| 			return static::successResponse($folder); | ||||
| 		} | ||||
|  | ||||
| 		return static::successResponse($folder); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @Route("/folders/{id}/notes") | ||||
| 	 */ | ||||
| 	public function linkAction($id, Request $request) { | ||||
| 		$folder = Folder::find(Folder::unhex($id)); | ||||
| 		if (!$folder) return static::errorResponse('Not found', 0, 404); | ||||
|  | ||||
| 		if ($request->isMethod('GET')) { | ||||
| 			return static::successResponse($folder->notes()); | ||||
| 		} | ||||
|  | ||||
| 		if ($request->isMethod('POST')) { | ||||
| 			$ids = $this->multipleValues($request->request->get('id')); | ||||
| 			if (!count($ids)) static::errorResponse('id parameter is missing'); | ||||
| 			$ids = Folder::unhex($ids); | ||||
| 			$folder->add($ids); | ||||
|  | ||||
| 			return static::successResponse(); | ||||
| 		} | ||||
|  | ||||
| 		return static::errorResponse('Invalid method'); | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										71
									
								
								src/AppBundle/Controller/NotesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/AppBundle/Controller/NotesController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Controller; | ||||
|  | ||||
| use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||||
| use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| use AppBundle\Controller\ApiController; | ||||
| use AppBundle\Model\Note; | ||||
|  | ||||
| class NotesController extends ApiController { | ||||
|  | ||||
| 	/** | ||||
| 	 * @Route("/notes") | ||||
| 	 */ | ||||
| 	public function allAction(Request $request) { | ||||
| 		if ($request->isMethod('POST')) { | ||||
| 			$note = new Note(); | ||||
| 			$note->fromPublicArray($request->request->all()); | ||||
| 			$note->owner_id = $this->user()->id; | ||||
| 			$note->save(); | ||||
| 			return static::successResponse($note->toPublicArray()); | ||||
| 		} | ||||
|  | ||||
| 		return static::errorResponse('Invalid method'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @Route("/notes/{id}") | ||||
| 	 */ | ||||
| 	public function oneAction($id, Request $request) { | ||||
| 		$note = Note::find(Note::unhex($id)); | ||||
| 		if (!$note && !$request->isMethod('PUT')) return static::errorResponse('Not found', 0, 404);	 | ||||
|  | ||||
| 		if ($request->isMethod('GET')) { | ||||
| 			return static::successResponse($note); | ||||
| 		} | ||||
|  | ||||
| 		if ($request->isMethod('PUT')) { | ||||
| 			$data = $this->putParameters(); | ||||
| 			$isNew = !$note; | ||||
| 			if ($isNew) $note = new Note(); | ||||
| 			foreach ($data as $n => $v) { | ||||
| 				if ($n == 'parent_id') $v = Note::unhex($v); | ||||
| 				$note->{$n} = $v; | ||||
| 			} | ||||
| 			$note->id = Note::unhex($id); | ||||
| 			$note->owner_id = $this->user()->id; | ||||
| 			$note->setIsNew($isNew); | ||||
| 			$note->save(); | ||||
| 			return static::successResponse($note); | ||||
| 		} | ||||
|  | ||||
| 		if ($request->isMethod('PATCH')) { | ||||
| 			$data = $this->patchParameters(); | ||||
| 			foreach ($data as $n => $v) { | ||||
| 				$note->{$n} = $v; | ||||
| 			} | ||||
| 			$note->save(); | ||||
| 			return static::successResponse($note); | ||||
| 		} | ||||
|  | ||||
| 		if ($request->isMethod('DELETE')) { | ||||
| 			$note->delete(); | ||||
| 			return static::successResponse(); | ||||
| 		} | ||||
|  | ||||
| 		return static::errorResponse('Invalid method'); | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/AppBundle/Controller/SessionsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/AppBundle/Controller/SessionsController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Controller; | ||||
|  | ||||
| use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||||
| use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| use AppBundle\Controller\ApiController; | ||||
| use AppBundle\Model\User; | ||||
| use AppBundle\Model\Session; | ||||
| use AppBundle\Exception\NotFoundException; | ||||
| use AppBundle\Exception\MethodNotAllowedException; | ||||
|  | ||||
|  | ||||
| use AppBundle\Model\Action; | ||||
|  | ||||
| class SessionsController extends ApiController { | ||||
|  | ||||
| 	/** | ||||
| 	 * @Route("/sessions") | ||||
| 	 */ | ||||
| 	public function allAction(Request $request) { | ||||
| 		if ($request->isMethod('POST')) { | ||||
| 			$data = $request->request->all(); | ||||
| 			// Note: the login method will throw an exception in case of failure | ||||
| 			$session = Session::login($data['email'], $data['password'], Session::unhex($data['client_id'])); | ||||
| 			return static::successResponse($session); | ||||
| 		} | ||||
|  | ||||
| 		throw new MethodNotAllowedException(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @Route("/sessions/{id}", name="one_session") | ||||
| 	 */ | ||||
| 	public function oneAction($id, Request $request) { | ||||
| 		$session = Session::find(Session::unhex($id)); | ||||
| 		if (!$session) throw new NotFoundException(); | ||||
| 		return static::successResponse($session); | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										114
									
								
								src/AppBundle/Controller/SynchronizerController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/AppBundle/Controller/SynchronizerController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Controller; | ||||
|  | ||||
| use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||||
| use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| use AppBundle\Controller\ApiController; | ||||
| use AppBundle\Model\Action; | ||||
| use AppBundle\Exception\UnauthorizedException; | ||||
|  | ||||
| /* | ||||
|  | ||||
| JS | ||||
|  | ||||
|  | ||||
| class Session | ||||
| 	::login() | ||||
|  | ||||
| class Synchronizer | ||||
| 	::fromId(id) | ||||
|  | ||||
| class Note | ||||
|  | ||||
| class User | ||||
|  | ||||
|  | ||||
| HISTORY | ||||
|  | ||||
| client_id, create, type, id => get full object from api | ||||
| update, type, id => get full object from api | ||||
| delete, type, id => remove object | ||||
|  | ||||
| Revisions | ||||
| ---------------- | ||||
| id | ||||
| client_id | ||||
| (user_id ?) | ||||
| action (create, update, delete) | ||||
| item_type (note, folder) | ||||
| item_field (title, body, completed...) | ||||
| item_id | ||||
|  | ||||
| if current client ID = revision.client_id - skip | ||||
|  | ||||
| Current client id = 123 | ||||
|  | ||||
| Client ID | Action | Item ID | ||||
| ------------------------------------ | ||||
| 456         delete   777 | ||||
| 123         update   777 - conflict - move to folder - note that deleted by X and then modified by Y | ||||
|  | ||||
|  | ||||
| Client ID | Action | Item ID         | Rev ID | ||||
| ------------------------------------------------------ | ||||
| 456         update   777             | 2 | ||||
| 123         update   777 - conflict  | 3 | ||||
|  | ||||
| Find rev 1 and do three way merge with 2 and 3 - means there's a need to store history of all versions of body/title | ||||
|  | ||||
|  | ||||
|  | ||||
| // Each item should have a revision ID. | ||||
| // When processing revisions => if item revision = revision.id - skip | ||||
|  | ||||
|  | ||||
| API CALL | ||||
|  | ||||
| /synchronizer/?last_id=<last_id_that_caller_synched_to> | ||||
|  | ||||
| SIMPLE IMPLEMENTATION: | ||||
|  | ||||
| loop through changes | ||||
| create list of actions: | ||||
| 	create one action per item ID / field (by merging all into one) | ||||
|  | ||||
| loop through actions | ||||
| skip current client id = action.client_id | ||||
|  | ||||
| send back list: | ||||
|  | ||||
| { | ||||
| 	sync_id: 132456, | ||||
| 	notes: [ | ||||
| 		{ | ||||
| 			action: 'update', | ||||
| 			field: 'body', | ||||
| 			body: 'blabla' | ||||
| 		} | ||||
| 	], | ||||
| 	has_more: true | ||||
| } | ||||
|  | ||||
| If has_more, resume with last sync_id | ||||
|  | ||||
|  | ||||
|  | ||||
| */ | ||||
|  | ||||
| class SynchronizerController extends ApiController { | ||||
|  | ||||
| 	/** | ||||
| 	 * @Route("/synchronizer") | ||||
| 	 */ | ||||
| 	public function allAction(Request $request) { | ||||
| 		$id = (int)$request->query->get('last_id'); | ||||
|  | ||||
| 		if (!$this->user() || !$this->session()) throw new UnauthorizedException(); | ||||
|  | ||||
| 		$actions = Action::actionsDoneAfterId($this->user()->id, $this->session()->client_id, $id); | ||||
| 		return static::successResponse($actions); | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										209
									
								
								src/AppBundle/Controller/UsersController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								src/AppBundle/Controller/UsersController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,209 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Controller; | ||||
|  | ||||
| use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||||
| use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| use AppBundle\Controller\ApiController; | ||||
| use AppBundle\Model\User; | ||||
| use AppBundle\Model\Session; | ||||
| use AppBundle\Model\Change; | ||||
| use AppBundle\Model\FolderItem; | ||||
| use AppBundle\Exception\ValidationException; | ||||
|  | ||||
|  | ||||
| use AppBundle\Diff; | ||||
|  | ||||
| use DiffMatchPatch\DiffMatchPatch; | ||||
|  | ||||
|  | ||||
|  | ||||
| class UsersController extends ApiController { | ||||
|  | ||||
| 	/** | ||||
| 	 * @Route("/users") | ||||
| 	 */ | ||||
| 	public function allAction(Request $request) { | ||||
|  | ||||
|  | ||||
|  | ||||
| 		$source = "This is the first line.\n\nThis is the second line."; | ||||
| 		$target1 = "This is the first line XXX.\n\nThis is the second line."; | ||||
| 		$target2 = "This is the first line.\n\nThis is the second line YYY."; | ||||
|  | ||||
| 		$r = Diff::merge3($source, $target1, $target2); | ||||
| 		var_dump($r);die(); | ||||
|  | ||||
|  | ||||
| 		// $dmp = new DiffMatchPatch(); | ||||
| 		// $patches = $dmp->patch_make($source, $target1); | ||||
| 		// // @@ -1,11 +1,12 @@ | ||||
| 		// //  Th | ||||
| 		// // -e | ||||
| 		// // +at | ||||
| 		// //   quick b | ||||
| 		// // @@ -22,18 +22,17 @@ | ||||
| 		// //  jump | ||||
| 		// // -s | ||||
| 		// // +ed | ||||
| 		// //   over | ||||
| 		// // -the | ||||
| 		// // +a | ||||
| 		// //   laz | ||||
| 		// $result = $dmp->patch_apply($patches, $target2); | ||||
| 		// var_dump($result); | ||||
| 		// die(); | ||||
|  | ||||
| 		// $dmp = new DiffMatchPatch(); | ||||
|  | ||||
| 		// $source = "This is the first line.\n\nThis is the second line."; | ||||
| 		// $target1 = "This is the first line XXX.\n\nThis is the second line."; | ||||
| 		// $target2 = "edsùfrklq lkzerlmk zemlkrmzlkerm lze."; | ||||
|  | ||||
|  | ||||
| 		// $diff1 = $dmp->patch_make($source, $target1); | ||||
| 		// $diff2 = $dmp->patch_make($source, $target2); | ||||
|  | ||||
| 		// //var_dump($dmp->patch_toText($diff1)); | ||||
| 		// // //var_dump($diff1[0]->patch_toText()); | ||||
|  | ||||
| 		// $r = $dmp->patch_apply($diff1, $source); | ||||
| 		// $r = $dmp->patch_apply($diff1, $target2); | ||||
| 		// var_dump($r);die(); | ||||
|  | ||||
| 		// $r = $dmp->patch_apply($diff2, $r[0]); | ||||
|  | ||||
| 		// var_dump($r); | ||||
|  | ||||
|  | ||||
| 		// $dmp = new DiffMatchPatch(); | ||||
| 		// $patches = $dmp->patch_make($source, $target1); | ||||
| 		// // @@ -1,11 +1,12 @@ | ||||
| 		// //  Th | ||||
| 		// // -e | ||||
| 		// // +at | ||||
| 		// //   quick b | ||||
| 		// // @@ -22,18 +22,17 @@ | ||||
| 		// //  jump | ||||
| 		// // -s | ||||
| 		// // +ed | ||||
| 		// //   over | ||||
| 		// // -the | ||||
| 		// // +a | ||||
| 		// //   laz | ||||
| 		// $result = $dmp->patch_apply($patches, $target2); | ||||
| 		// var_dump($result); | ||||
|  | ||||
| 		// die(); | ||||
|  | ||||
| 		// $r = Diff::merge($source, $target1, $target2); | ||||
| 		// var_dump($r);die(); | ||||
|  | ||||
| 		// $diff1 = xdiff_string_diff($source, $target1); | ||||
| 		// $diff2 = xdiff_string_diff($source, $target2); | ||||
|  | ||||
| 		// $errors = array(); | ||||
| 		// $t = xdiff_string_merge3($source , $target1, $target2, $errors); | ||||
| 		// var_dump($errors); | ||||
| 		// var_dump($t);die(); | ||||
|  | ||||
| 		// var_dump($diff1); | ||||
| 		// var_dump($diff2); | ||||
|  | ||||
| 		// $errors = array(); | ||||
| 		// $t = xdiff_string_patch($source, $diff1, XDIFF_PATCH_NORMAL, $errors); | ||||
| 		// var_dump($t); | ||||
| 		// var_dump($errors); | ||||
|  | ||||
| 		// $errors = array(); | ||||
| 		// $t = xdiff_string_patch($t, $diff2, XDIFF_PATCH_NORMAL, $errors); | ||||
| 		// var_dump($t); | ||||
| 		// var_dump($errors); | ||||
|  | ||||
|  | ||||
|  | ||||
| 		// var_dump($diff1); | ||||
| 		// var_dump($diff2); | ||||
|  | ||||
| 		// $change = new Change(); | ||||
| 		// $change->user_id = FolderItem::unhex('204705F2E2E698036034FDC709840B80'); | ||||
| 		// $change->client_id = FolderItem::unhex('11111111111111111111111111111111'); | ||||
| 		// $change->item_type = FolderItem::enumId('type', 'note'); | ||||
| 		// $change->item_field = FolderItem::enumId('field', 'title'); | ||||
| 		// $change->item_id = FolderItem::unhex('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD'); | ||||
| 		// $change->delta = 'salut ca va'; | ||||
| 		// $change->save(); | ||||
|  | ||||
|  | ||||
| 		// $change = new Change(); | ||||
| 		// $change->user_id = FolderItem::unhex('204705F2E2E698036034FDC709840B80'); | ||||
| 		// $change->client_id = FolderItem::unhex('11111111111111111111111111111111'); | ||||
| 		// $change->item_type = FolderItem::enumId('type', 'note'); | ||||
| 		// $change->item_field = FolderItem::enumId('field', 'title'); | ||||
| 		// $change->item_id = FolderItem::unhex('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD'); | ||||
| 		// $change->createDelta('salut, ça va ? oui très bien'); | ||||
| 		// $change->save(); | ||||
|  | ||||
| 		// $change = new Change(); | ||||
| 		// $change->user_id = FolderItem::unhex('204705F2E2E698036034FDC709840B80'); | ||||
| 		// $change->client_id = FolderItem::unhex('11111111111111111111111111111111'); | ||||
| 		// $change->item_type = FolderItem::enumId('type', 'note'); | ||||
| 		// $change->item_field = FolderItem::enumId('field', 'title'); | ||||
| 		// $change->item_id = FolderItem::unhex('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD'); | ||||
| 		// $change->createDelta('salut - oui très bien'); | ||||
| 		// $change->save(); | ||||
|  | ||||
| 		// $change = new Change(); | ||||
| 		// $change->user_id = FolderItem::unhex('204705F2E2E698036034FDC709840B80'); | ||||
| 		// $change->client_id = FolderItem::unhex('11111111111111111111111111111111'); | ||||
| 		// $change->item_type = FolderItem::enumId('type', 'note'); | ||||
| 		// $change->item_field = FolderItem::enumId('field', 'title'); | ||||
| 		// $change->item_id = FolderItem::unhex('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD'); | ||||
| 		// $change->createDelta('salut, ça va ? oui bien'); | ||||
| 		// $change->save(); | ||||
|  | ||||
|  | ||||
|  | ||||
| 		$d = Change::fullFieldText(FolderItem::unhex('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD'), FolderItem::enumId('field', 'title')); | ||||
| 		var_dump($d);die(); | ||||
|  | ||||
|  | ||||
|  | ||||
| 		die(); | ||||
|  | ||||
|  | ||||
| 		// $fineDiff = $this->get('app.fine_diff'); | ||||
| 		// $opcodes = $fineDiff->getDiffOpcodes('salut ca va', 'salut va?'); | ||||
| 		// var_dump($opcodes); | ||||
| 		// $merged = $fineDiff->renderToTextFromOpcodes('salut ca va', $opcodes); | ||||
| 		// var_dump($merged); | ||||
| 		// die(); | ||||
|  | ||||
| 		if ($request->isMethod('POST')) { | ||||
| 			$user = new User(); | ||||
| 			$data = $request->request->all(); | ||||
|  | ||||
| 			$errors = User::validate($data); | ||||
| 			if (count($errors)) throw ValidationException::fromErrors($errors); | ||||
|  | ||||
| 			$data['password'] = Session::hashPassword($data['password']); | ||||
| 			$user->fromPublicArray($data); | ||||
| 			$user->save(); | ||||
| 			return static::successResponse($user->toPublicArray()); | ||||
| 		} | ||||
|  | ||||
| 		return static::errorResponse('Invalid method'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @Route("/users/{id}") | ||||
| 	 */ | ||||
| 	public function oneAction($id, Request $request) { | ||||
| 		$user = User::find(User::unhex($id)); | ||||
| 		if (!$user) return static::errorResponse('Not found', 0, 404); | ||||
| 		$this->aclCheck($user); | ||||
| 		return static::successResponse($user); | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										33
									
								
								src/AppBundle/Diff.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/AppBundle/Diff.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle; | ||||
|  | ||||
| use DiffMatchPatch\DiffMatchPatch; | ||||
|  | ||||
| class Diff { | ||||
|  | ||||
| 	static private $dmp_ = null; | ||||
|  | ||||
| 	static private function dmp() { | ||||
| 		if (self::$dmp_) return self::$dmp_; | ||||
| 		self::$dmp_ = new DiffMatchPatch(); | ||||
| 		return self::$dmp_; | ||||
| 	} | ||||
|  | ||||
| 	static public function diff($from, $to) { | ||||
| 		return self::dmp()->patch_toText(self::dmp()->patch_make($from, $to)); | ||||
| 	} | ||||
|  | ||||
| 	static public function patch($from, $diff) { | ||||
| 		return self::dmp()->patch_apply(self::dmp()->patch_fromText($diff), $from); | ||||
| 	} | ||||
|  | ||||
| 	// Basically applies diff(orginal, mod1) to mod2. Note sure if this is really | ||||
| 	// equivalent to a three-way merge. | ||||
| 	static public function merge3($original, $modified1, $modified2) { | ||||
| 		$patches = self::dmp()->patch_make($original, $modified1); | ||||
| 		return self::dmp()->patch_apply($patches, $modified2); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| } | ||||
							
								
								
									
										30
									
								
								src/AppBundle/Eloquent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/AppBundle/Eloquent.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle; | ||||
|  | ||||
| class Eloquent { | ||||
|  | ||||
| 	private $capsule_ = null; | ||||
|  | ||||
| 	public function __construct() { | ||||
| 		$this->capsule_ = new \Illuminate\Database\Capsule\Manager(); | ||||
|  | ||||
| 		$this->capsule_->addConnection([ | ||||
| 			'driver'    => 'mysql', | ||||
| 			'host'      => 'localhost', | ||||
| 			'database'  => 'notes', | ||||
| 			'username'  => 'root', | ||||
| 			'password'  => 'pass', | ||||
| 			'charset'   => 'utf8', | ||||
| 			'collation' => 'utf8_unicode_ci', | ||||
| 			'prefix'    => '', | ||||
| 		]); | ||||
|  | ||||
| 		$this->capsule_->bootEloquent(); | ||||
| 	} | ||||
|  | ||||
| 	public function connection() { | ||||
| 		return $this->capsule_->getConnection('default'); | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/AppBundle/Exception/AuthException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/AppBundle/Exception/AuthException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Exception; | ||||
|  | ||||
| class AuthException extends BaseException { | ||||
|  | ||||
| 	protected $message = 'invalid authentication'; | ||||
|  | ||||
| } | ||||
							
								
								
									
										36
									
								
								src/AppBundle/Exception/BaseException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/AppBundle/Exception/BaseException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Exception; | ||||
|  | ||||
| use Symfony\Component\HttpFoundation\JsonResponse; | ||||
|  | ||||
| class BaseException extends \Exception { | ||||
|  | ||||
| 	protected $httpStatusCode = 400; | ||||
|  | ||||
| 	public function getType() { | ||||
| 		$t = str_replace('Exception', '', get_called_class()); | ||||
| 		$t = str_replace("AppBundle\\\\", '', $t); | ||||
| 		return $t; | ||||
| 	} | ||||
|  | ||||
| 	public function getHttpStatusCode() { | ||||
| 		return $this->httpStatusCode; | ||||
| 	} | ||||
|  | ||||
| 	public function toErrorArray() { | ||||
| 		$o = array(); | ||||
| 		$o['error'] = $this->getMessage(); | ||||
| 		if ($this->getCode()) $o['code'] = $this->getCode(); | ||||
| 		$o['type'] = $this->getType(); | ||||
| 		return $o; | ||||
| 	} | ||||
|  | ||||
| 	public function toJsonResponse($errorObject = null) { | ||||
| 		if (!$errorObject) $errorObject = $this->toErrorArray(); | ||||
| 		$response = new JsonResponse($errorObject); | ||||
| 		$response->setStatusCode($this->getHttpStatusCode()); | ||||
| 		return $response; | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/AppBundle/Exception/ForbiddenException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/AppBundle/Exception/ForbiddenException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Exception; | ||||
|  | ||||
| class ForbiddenException extends BaseException { | ||||
|  | ||||
| 	protected $message = 'forbidden'; | ||||
| 	protected $httpStatusCode = 403; | ||||
|  | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/AppBundle/Exception/MethodNotAllowedException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/AppBundle/Exception/MethodNotAllowedException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Exception; | ||||
|  | ||||
| class MethodNotAllowedException extends BaseException { | ||||
|  | ||||
| 	protected $message = 'method not allowed'; | ||||
| 	protected $httpStatusCode = 405; | ||||
|  | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/AppBundle/Exception/NotFoundException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/AppBundle/Exception/NotFoundException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Exception; | ||||
|  | ||||
| class NotFoundException extends BaseException { | ||||
|  | ||||
| 	protected $message = 'not found'; | ||||
| 	protected $httpStatusCode = 400; | ||||
|  | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/AppBundle/Exception/UnauthorizedException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/AppBundle/Exception/UnauthorizedException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Exception; | ||||
|  | ||||
| class UnauthorizedException extends BaseException { | ||||
|  | ||||
| 	protected $message = 'unauthorized'; | ||||
| 	protected $httpStatusCode = 401; | ||||
|  | ||||
| } | ||||
							
								
								
									
										23
									
								
								src/AppBundle/Exception/ValidationException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/AppBundle/Exception/ValidationException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Exception; | ||||
|  | ||||
| class ValidationException extends BaseException { | ||||
|  | ||||
| 	protected $message = 'validation error'; | ||||
| 	public $validationErrors = array(); | ||||
|  | ||||
| 	static public function fromErrors($errors) { | ||||
| 		if (!count($errors)) return new ValidationException(); | ||||
| 		$e = new ValidationException($errors[0]['message']); | ||||
| 		$e->validationErrors = $errors; | ||||
| 		return $e; | ||||
| 	} | ||||
|  | ||||
| 	public function toErrorArray() { | ||||
| 		$o = parent::toErrorArray(); | ||||
| 		$o['validation_errors'] = $this->validationErrors; | ||||
| 		return $o; | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										28
									
								
								src/AppBundle/Model/Action.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/AppBundle/Model/Action.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Model; | ||||
|  | ||||
| class Action extends BaseModel { | ||||
|  | ||||
| 	static protected $enums = array( | ||||
| 		'type' => array('create', 'update', 'delete'), | ||||
| 	); | ||||
|  | ||||
| 	static public function actionsDoneAfterId($userId, $clientId, $actionId) { | ||||
| 		$limit = 100; | ||||
| 		$items = self::where('id', '>', $actionId) | ||||
| 		             ->where('user_id', '=', $userId) | ||||
| 		             ->where('client_id', '!=', $clientId) | ||||
| 		             ->orderBy('id') | ||||
| 		             ->limit($limit + 1) | ||||
| 		             ->get(); | ||||
| 		$hasMore = $limit < count($items); | ||||
| 		if ($hasMore) array_pop($items); | ||||
|  | ||||
| 		return array( | ||||
| 			'has_more' => $hasMore, | ||||
| 			'items' => $items, | ||||
| 		); | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
							
								
								
									
										286
									
								
								src/AppBundle/Model/BaseModel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								src/AppBundle/Model/BaseModel.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,286 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Model; | ||||
|  | ||||
| use \Illuminate\Database\Eloquent\Model; | ||||
| use \Illuminate\Support\Facades\DB; | ||||
|  | ||||
| class BaseModel extends \Illuminate\Database\Eloquent\Model { | ||||
|  | ||||
| 	public $timestamps = false; | ||||
| 	public $useUuid = false; | ||||
| 	protected $changedVersionedFieldValues = array(); | ||||
| 	protected $versionedFields = array(); | ||||
| 	private $isNew = null; | ||||
| 	private $revId = 0; | ||||
|  | ||||
| 	static private $clientId = null; | ||||
| 	static protected $enums = array( | ||||
| 		'field' => array('title', 'body', 'completed'), | ||||
| 	); | ||||
| 	static protected $defaultValidationRules = array(); | ||||
| 	static protected $defaultValidationMessages = array( | ||||
| 		'required' => '{key} is required', | ||||
| 		'notEmpty' => '{key} cannot be empty', | ||||
| 		'minLength' => '{key} must be at least {arg0} characters long', | ||||
| 		'maxLength' => '{key} must not be longer than {arg0} characters', | ||||
| 		'function' => '{key} is invalid', | ||||
| 	); | ||||
|  | ||||
| 	public function __construct($attributes = array()) { | ||||
| 		parent::__construct($attributes); | ||||
| 	} | ||||
|  | ||||
| 	static public function setClientId($clientId) { | ||||
| 		self::$clientId = $clientId; | ||||
| 	} | ||||
|  | ||||
| 	static public function clientId() { | ||||
| 		return self::$clientId; | ||||
| 	} | ||||
|  | ||||
| 	public function fromPublicArray($array) { | ||||
| 		foreach ($array as $k => $v) { | ||||
| 			if ($k == 'rev_id') { | ||||
| 				$this->revId = $v; | ||||
| 			} else if (in_array($k, $this->versionedFields)) { | ||||
| 				$this->changedVersionedFieldValues[$k] = $v; | ||||
| 			} else { | ||||
| 				$this->{$k} = $v; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public function toPublicArray() { | ||||
| 		$output = $this->toArray(); | ||||
| 		if ($this->useUuid) { | ||||
| 			$output['id'] = self::hex($output['id']); | ||||
| 		} | ||||
| 		 | ||||
| 		if (!empty($output['parent_id'])) $output['parent_id'] = self::hex($output['parent_id']); | ||||
| 		if (!empty($output['owner_id'])) $output['owner_id'] = self::hex($output['owner_id']); | ||||
| 		if (!empty($output['client_id'])) $output['client_id'] = self::hex($output['client_id']); | ||||
| 		if (!empty($output['item_id'])) $output['item_id'] = self::hex($output['item_id']); | ||||
| 		if (!empty($output['user_id'])) $output['user_id'] = self::hex($output['user_id']); | ||||
|  | ||||
| 		foreach ($output as $k => $v) { | ||||
| 			if (isset(static::$enums[$k])) { | ||||
| 				$output[$k] = static::enumName($k, $v); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (isset($output['item_type'])) { | ||||
| 			$output['item_type'] = FolderItem::enumName('type', $output['item_type'], true); | ||||
| 		} | ||||
|  | ||||
| 		if (isset($output['item_field'])) { | ||||
| 			$output['item_field'] = BaseModel::enumName('field', $output['item_field'], true); | ||||
| 		} | ||||
|  | ||||
| 		$maxRevId = 0; | ||||
| 		foreach ($this->versionedFields as $field) { | ||||
| 			$r = $this->versionedFieldValue($field, true); | ||||
| 			$output[$field] = $r['text']; | ||||
| 			$maxRevId = max($maxRevId, $r['revId']); | ||||
| 		} | ||||
|  | ||||
| 		$output['rev_id'] = $maxRevId; | ||||
|  | ||||
| 		return $output; | ||||
| 	} | ||||
|  | ||||
| 	public function versionedFieldValue($fieldName, $returnRevId = false) { | ||||
| 		return Change::fullFieldText($this->id, BaseModel::enumId('field', $fieldName), null, $returnRevId); | ||||
| 	} | ||||
|  | ||||
| 	public function setVersionedFieldValue($fieldName, $fieldValue) { | ||||
| 		$this->changedVersionedFieldValues[$fieldName] = $fieldValue; | ||||
| 	} | ||||
|  | ||||
| 	static public function createId() { | ||||
| 		return openssl_random_pseudo_bytes(16); | ||||
| 	} | ||||
|  | ||||
| 	static public function hex($id) { | ||||
| 		if (is_array($id)) { | ||||
| 			foreach ($id as $k => $v) { | ||||
| 				$id[$k] = self::hex($v); | ||||
| 			} | ||||
| 			return $id; | ||||
| 		} | ||||
| 		return bin2hex($id); | ||||
| 	} | ||||
|  | ||||
| 	static public function unhex($s) { | ||||
| 		if (!strlen($s)) return null; | ||||
| 		 | ||||
| 		if (is_array($s)) { | ||||
| 			foreach ($s as $k => $v) { | ||||
| 				$s[$k] = self::unhex($v); | ||||
| 			} | ||||
| 			return $s; | ||||
| 		} | ||||
| 		$output = @hex2bin($s); | ||||
| 		if ($output === false) return null; | ||||
| 		return $output; | ||||
| 	} | ||||
|  | ||||
| 	public function owner() { | ||||
| 		if (!isset($this->owner_id)) return null; | ||||
| 		return User::find($this->owner_id); | ||||
| 	} | ||||
|  | ||||
| 	static public function validate($data, $rules = null) { | ||||
| 		if (!$rules) $rules = static::$defaultValidationRules; | ||||
|  | ||||
| 		$errors = array(); | ||||
| 		 | ||||
| 		foreach ($rules as $key => $keyRules) { | ||||
| 			foreach ($keyRules as $rule) { | ||||
| 				$ok = true; | ||||
| 				switch ($rule['type']) { | ||||
|  | ||||
| 					case 'required': | ||||
|  | ||||
| 						if (!array_key_exists($key, $data)) $ok = false; | ||||
| 						break; | ||||
|  | ||||
| 					case 'notEmpty': | ||||
|  | ||||
| 						if (array_key_exists($key, $data) && !strlen((string)$data[$key])) $ok = false; | ||||
| 						break; | ||||
|  | ||||
| 					case 'minLength': | ||||
|  | ||||
| 						if (array_key_exists($key, $data) && strlen((string)$data[$key]) < $rule['args'][0]) $ok = false; | ||||
| 						break; | ||||
|  | ||||
| 					case 'maxLength': | ||||
|  | ||||
| 						if (array_key_exists($key, $data) && strlen((string)$data[$key]) > $rule['args'][0]) $ok = false; | ||||
| 						break; | ||||
|  | ||||
| 					case 'function': | ||||
|  | ||||
| 						$ok = call_user_func_array($rule['args'][0], array($key, $rule, $data)); | ||||
| 						break; | ||||
|  | ||||
| 					default: | ||||
|  | ||||
| 						throw new \Exception(sprintf('unsupported validation rule: "%s"', $rule['name'])); | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 				if (!$ok) { | ||||
| 					$errors[] = array( | ||||
| 						'key' => $key, | ||||
| 						'type' => $rule['type'] == 'function' ? 'other' : $rule['type'], | ||||
| 						'message' => static::validationMessage($key, $rule, $data), | ||||
| 					); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return $errors; | ||||
| 	} | ||||
|  | ||||
| 	static public function validationMessage($key, $rule, $data) { | ||||
| 		$msg = static::$defaultValidationMessages[$rule['type']]; | ||||
| 		if (isset($rule['message'])) $msg = $rule['message']; | ||||
| 		$msg = str_replace('{key}', $key, $msg); | ||||
| 		$msg = str_replace('{value}', isset($data[$key]) ? $data[$key] : '', $msg); | ||||
| 		$args = isset($rule['args']) ? $rule['args'] : array(); | ||||
| 		for ($i = 0; $i < count($args); $i++) { | ||||
| 			$v = $args[$i]; | ||||
| 			if (is_array($v)) $v = ''; | ||||
| 			if (is_object($v) && !method_exists($v, '__toString')) $v = ''; | ||||
| 			$v = (string)$v; | ||||
| 			$msg = str_replace(sprintf('{arg%s}', $i), $v, $msg); | ||||
| 		} | ||||
| 		return $msg; | ||||
| 	} | ||||
|  | ||||
| 	static public function enumName($enumType, $enumId, $returnNullOnError = false) { | ||||
| 		foreach (static::$enums[$enumType] as $index => $name) { | ||||
| 			if ($index + 1 == $enumId) return $name; | ||||
| 		} | ||||
| 		if ($returnNullOnError) return null; | ||||
| 		throw new \Exception(sprintf('Invalid enum: %s/%s', $enumType, $enumId)); | ||||
| 	} | ||||
|  | ||||
| 	static public function enumId($enumType, $enumName, $returnNullOnError = false) { | ||||
| 		if (!isset(static::$enums[$enumType])) throw new \Exception(sprintf('Invalid enum type: %s', $enumType)); | ||||
| 		foreach (static::$enums[$enumType] as $index => $name) { | ||||
| 			if ($name == $enumName) return $index + 1; | ||||
| 		} | ||||
| 		if ($returnNullOnError) return null; | ||||
| 		throw new \Exception(sprintf('Invalid enum: %s/%s', $enumType, $enumName)); | ||||
| 	} | ||||
|  | ||||
| 	// Allows caller to force the model to be detected as new, | ||||
| 	// even when the model already has an ID (to handle PUT | ||||
| 	// calls that manually set the ID). | ||||
| 	public function setIsNew($v) { | ||||
| 		$this->isNew = $v; | ||||
| 	} | ||||
|  | ||||
| 	public function save(Array $options = array()) { | ||||
| 		$isNew = !$this->id || $this->isNew === true; | ||||
|  | ||||
| 		if ($this->useUuid && $isNew && !$this->id) $this->id = self::createId(); | ||||
| 		$this->updated_time = time(); // TODO: maybe only update if one of the fields, or if some of versioned data has changed | ||||
| 		if ($isNew) $this->created_time = time(); | ||||
|  | ||||
| 		parent::save($options); | ||||
|  | ||||
| 		if (count($this->versionedFields)) { | ||||
| 			$this->recordChanges($isNew ? 'create' : 'update', $this->changedVersionedFieldValues); | ||||
| 		} | ||||
| 		$this->changedVersionedFieldValues = array(); | ||||
| 	} | ||||
|  | ||||
| 	public function delete() { | ||||
| 		parent::delete(); | ||||
|  | ||||
| 		if (count($this->versionedFields)) { | ||||
| 			$this->recordChanges('delete'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	protected function recordChanges($type, $versionedData = array()) { | ||||
| 		if ($type == 'delete') { | ||||
| 			$change = $this->newChange($type); | ||||
| 			$change->save(); | ||||
| 		} else if ($type == 'create' || $type == 'update') { | ||||
| 			foreach ($this->versionedFields as $field) { | ||||
| 				if (!isset($versionedData[$field])) continue; | ||||
|  | ||||
| 				$change = $this->newChange($type); | ||||
| 				$change->item_field = BaseModel::enumId('field', $field); | ||||
| 				$change->createDelta($versionedData[$field]); | ||||
| 				$change->save(); | ||||
| 			} | ||||
| 		} else { | ||||
| 			throw new \Exception('Unknown type: ' . $type); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private function classItemTypeName() { | ||||
| 		$s = strtolower(get_called_class()); | ||||
| 		$s = explode("\\", $s); | ||||
| 		return $s[count($s) - 1]; | ||||
| 	} | ||||
|  | ||||
| 	private function newChange($type) { | ||||
| 		if (static::clientId() === null) throw new \Exception('Client ID must be specified'); | ||||
|  | ||||
| 		$change = new Change(); | ||||
| 		$change->user_id = $this->owner_id; | ||||
| 		$change->client_id = static::clientId(); | ||||
| 		$change->item_type = FolderItem::enumId('type', $this->classItemTypeName()); | ||||
| 		$change->type = Change::enumId('type', $type); | ||||
| 		$change->item_id = $this->id; | ||||
| 		return $change; | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										62
									
								
								src/AppBundle/Model/Change.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/AppBundle/Model/Change.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Model; | ||||
|  | ||||
| use AppBundle\Diff; | ||||
|  | ||||
| class Change extends BaseModel { | ||||
|  | ||||
| 	static protected $enums = array( | ||||
| 		'type' => array('create', 'update', 'delete'), | ||||
| 	); | ||||
|  | ||||
| 	static public function changesDoneAfterId($userId, $clientId, $changeId) { | ||||
| 		$limit = 100; | ||||
| 		$items = self::where('id', '>', $changeId) | ||||
| 		             ->where('user_id', '=', $userId) | ||||
| 		             ->where('client_id', '!=', $clientId) | ||||
| 		             ->orderBy('id') | ||||
| 		             ->limit($limit + 1) | ||||
| 		             ->get(); | ||||
| 		$hasMore = $limit < count($items); | ||||
| 		if ($hasMore) array_pop($items); | ||||
|  | ||||
| 		return array( | ||||
| 			'has_more' => $hasMore, | ||||
| 			'items' => $items, | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| 	static public function itemFieldHistory($itemId, $itemField, $toId = null) { | ||||
| 		$query = self::where('item_id', '=', $itemId); | ||||
| 		$query->where('item_field', '=', $itemField); | ||||
| 		if ($toId) $query->where('id', '<=', $toId); | ||||
| 		$query->orderBy('id'); | ||||
| 		return $query->get(); | ||||
| 	} | ||||
|  | ||||
| 	static public function fullFieldText($itemId, $itemField, $toId = null, $returnRevId = false) { | ||||
| 		$output = ''; | ||||
| 		$changes = self::itemFieldHistory($itemId, $itemField, $toId); | ||||
| 		$revId = 0; | ||||
| 		for ($i = 0; $i < count($changes); $i++) { | ||||
| 			$change = $changes[$i]; | ||||
| 			$result = Diff::patch($output, $change->delta); | ||||
| 			if (!count($result[1])) throw new \Exception('Unexpected result format for patch operation: ' . json_encode($result)); | ||||
| 			if (!$result[1][0]) { | ||||
| 				// Could not patch the string. TODO: handle conflict | ||||
| 			} | ||||
| 			$output = $result[0]; | ||||
|  | ||||
| 			$revId = $change->id; | ||||
| 		} | ||||
|  | ||||
| 		return $returnRevId ? array('text' => $output, 'revId' => $revId) : $output; | ||||
| 	} | ||||
|  | ||||
| 	public function createDelta($newText) { | ||||
| 		$currentText = self::fullFieldText($this->item_id, $this->item_field, $this->previous_id); | ||||
| 		$this->delta = Diff::diff($currentText, $newText); | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
							
								
								
									
										21
									
								
								src/AppBundle/Model/Folder.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/AppBundle/Model/Folder.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Model; | ||||
|  | ||||
| class Folder extends FolderItem { | ||||
|  | ||||
| 	protected $versionedFields = array('title'); | ||||
|  | ||||
| 	public function add($ids) { | ||||
| 		$notes = Note::find($ids); | ||||
| 		foreach ($notes as $note) { | ||||
| 			$note->parent_id = $this->id; | ||||
| 			$note->save(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public function notes() { | ||||
| 		return Note::where('parent_id', '=', $this->id)->get(); | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										14
									
								
								src/AppBundle/Model/FolderItem.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/AppBundle/Model/FolderItem.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Model; | ||||
|  | ||||
| class FolderItem extends BaseModel { | ||||
|  | ||||
| 	public $useUuid = true; | ||||
| 	public $incrementing = false; | ||||
|  | ||||
| 	static protected $enums = array( | ||||
| 		'type' => array('folder', 'note', 'todo'), | ||||
| 	); | ||||
|  | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/AppBundle/Model/Note.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/AppBundle/Model/Note.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Model; | ||||
|  | ||||
| class Note extends FolderItem { | ||||
|  | ||||
| 	protected $versionedFields = array('title', 'body'); | ||||
|  | ||||
| } | ||||
							
								
								
									
										40
									
								
								src/AppBundle/Model/Session.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/AppBundle/Model/Session.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Model; | ||||
|  | ||||
| use AppBundle\Exception\NotFoundException; | ||||
| use AppBundle\Exception\AuthException; | ||||
|  | ||||
| class Session extends BaseModel { | ||||
|  | ||||
| 	public $useUuid = true; | ||||
| 	public $incrementing = false; | ||||
|  | ||||
| 	static public function hashPassword($password) { | ||||
| 		return password_hash($password, PASSWORD_DEFAULT); | ||||
| 	} | ||||
|  | ||||
| 	static public function verifyPassword($password, $hash) { | ||||
| 		return password_verify($password, $hash); | ||||
| 	} | ||||
|  | ||||
| 	static public function passwordMinLength() { | ||||
| 		return 8; | ||||
| 	} | ||||
|  | ||||
| 	static public function login($email, $password, $clientId) { | ||||
| 		$user = User::byEmail($email); | ||||
| 		if (!$user) throw new NotFoundException(); | ||||
|  | ||||
| 		$ok = self::verifyPassword($password, $user->password); | ||||
| 		if (!$ok) throw new AuthException(); | ||||
|  | ||||
| 		$session = new Session(); | ||||
| 		$session->owner_id = $user->id; | ||||
| 		$session->client_id = $clientId; | ||||
| 		$session->save(); | ||||
|  | ||||
| 		return $session; | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										52
									
								
								src/AppBundle/Model/User.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/AppBundle/Model/User.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| <?php | ||||
|  | ||||
| namespace AppBundle\Model; | ||||
|  | ||||
| use AppBundle\Exception\ValidationException; | ||||
|  | ||||
| class User extends BaseModel { | ||||
|  | ||||
| 	public $useUuid = true; | ||||
| 	public $incrementing = false; | ||||
|  | ||||
| 	public function __construct($attributes = array()) { | ||||
| 		parent::__construct($attributes); | ||||
|  | ||||
| 		static::$defaultValidationRules['email'] = array( | ||||
| 			array('type' => 'required'), | ||||
| 			array('type' => 'notEmpty'), | ||||
| 			array('type' => 'function', 'args' => array(array('AppBundle\Model\User', 'validateUniqueEmail')), 'message' => 'email "{value}" is already in use'), | ||||
| 		); | ||||
| 		static::$defaultValidationRules['password'] = array( | ||||
| 			array('type' => 'required'), | ||||
| 			array('type' => 'minLength', 'args' => array(8)), | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| 	public function toPublicArray() { | ||||
| 		$output = parent::toPublicArray(); | ||||
| 		unset($output['password']); | ||||
| 		return $output; | ||||
| 	} | ||||
|  | ||||
| 	public function byEmail($email) { | ||||
| 		return self::where('email', '=', $email)->first(); | ||||
| 	} | ||||
|  | ||||
| 	public function save(Array $options = array()) { | ||||
| 		$isNew = !$this->id; | ||||
|  | ||||
| 		parent::save($options); | ||||
| 		if ($isNew) { | ||||
| 			$this->owner_id = $this->id; | ||||
| 			parent::save($options); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static public function validateUniqueEmail($key, $rule, $data) { | ||||
| 		if (!isset($data['email'])) return true; | ||||
| 		$u = self::byEmail($data['email']); | ||||
| 		return !$u; | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										57
									
								
								structure.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								structure.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| CREATE TABLE `folders` ( | ||||
| 	`id` binary(16) NOT NULL, | ||||
| 	`created_time` int(11) NOT NULL default '0', | ||||
| 	`updated_time` int(11) NOT NULL default '0', | ||||
| 	`parent_id` binary(16) NULL default NULL, | ||||
| 	`owner_id` binary(16) NULL default NULL, | ||||
| 	`is_encrypted` tinyint(1) NOT NULL default '0', | ||||
| 	`encryption_method` int(11) NOT NULL default '0', | ||||
| PRIMARY KEY (`id`) | ||||
| ) CHARACTER SET=utf8; | ||||
|  | ||||
| CREATE TABLE `notes` ( | ||||
| 	`id` binary(16) NOT NULL, | ||||
| 	`completed` tinyint(1) NOT NULL default '0', | ||||
| 	`created_time` int(11) NOT NULL default '0', | ||||
| 	`updated_time` int(11) NOT NULL default '0', | ||||
| 	`parent_id` binary(16) NULL default NULL, | ||||
| 	`owner_id` binary(16), | ||||
| 	`is_encrypted` tinyint(1) NOT NULL default '0', | ||||
| 	`encryption_method` int(11) NOT NULL default '0', | ||||
| PRIMARY KEY (`id`) | ||||
| ) CHARACTER SET=utf8; | ||||
|  | ||||
| CREATE TABLE `users` ( | ||||
| 	`id` binary(16) NOT NULL, | ||||
| 	`email` varchar(256) NOT NULL default '', | ||||
| 	`password` varchar(256) NOT NULL default '', | ||||
| 	`validated` tinyint(1) NOT NULL default '0', | ||||
| 	`created_time` int(11) NOT NULL default '0', | ||||
| 	`updated_time` int(11) NOT NULL default '0', | ||||
| 	`owner_id` binary(16), | ||||
| PRIMARY KEY (`id`) | ||||
| ) CHARACTER SET=utf8; | ||||
|  | ||||
| CREATE TABLE `sessions` ( | ||||
| 	`id` binary(16) NOT NULL, | ||||
| 	`owner_id` binary(16), | ||||
| 	`client_id` binary(16), | ||||
| 	`created_time` int(11) NOT NULL default '0', | ||||
| 	`updated_time` int(11) NOT NULL default '0', | ||||
| PRIMARY KEY (`id`) | ||||
| ) CHARACTER SET=utf8; | ||||
|  | ||||
| CREATE TABLE `changes` ( | ||||
| 	`id` int(11) NOT NULL AUTO_INCREMENT, | ||||
| 	`user_id` binary(16), | ||||
| 	`client_id` binary(16), | ||||
| 	`created_time` int(11) NOT NULL default '0', | ||||
| 	`updated_time` int(11) NOT NULL default '0', | ||||
| 	`type` int(11) NOT NULL default '0', | ||||
| 	`item_id` binary(16), | ||||
| 	`item_type` int(11) NOT NULL default '0', | ||||
| 	`item_field` int(11) NOT NULL default '0', | ||||
| 	`delta` MEDIUMTEXT, | ||||
| 	`previous_id` int(11) NOT NULL default '0', | ||||
| PRIMARY KEY (`id`) | ||||
| ) CHARACTER SET=utf8; | ||||
							
								
								
									
										69
									
								
								tests/BaseTestCase.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								tests/BaseTestCase.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| <?php | ||||
|  | ||||
| use PHPUnit\Framework\TestCase; | ||||
|  | ||||
| use AppBundle\Model\BaseModel; | ||||
| use AppBundle\Model\User; | ||||
| use AppBundle\Model\Session; | ||||
|  | ||||
| class BaseTestCase extends TestCase { | ||||
|  | ||||
| 	protected function createModelId($type, $num = 1) { | ||||
| 		$c = ''; | ||||
| 		if ($type == 'user') { | ||||
| 			$c = 'A'; | ||||
| 		} else if ($type == 'client') { | ||||
| 			$c = 'C'; | ||||
| 		} else if ($type == 'session') { | ||||
| 			$c = 'B'; | ||||
| 		} else if ($type == 'note') { | ||||
| 			$c = 'D'; | ||||
| 		} | ||||
| 		return BaseModel::unhex(str_repeat($c . $num, 16)); | ||||
| 	} | ||||
|  | ||||
| 	protected function clientId($num = 1) { | ||||
| 		return $this->createModelId('client', $num); | ||||
| 	} | ||||
|  | ||||
| 	protected function user($num = 1) { | ||||
| 		$id = $this->createModelId('user', $num); | ||||
| 		$user = User::find($id); | ||||
| 		if ($user) return $user; | ||||
|  | ||||
| 		$user = new User(); | ||||
| 		$user->id = $id; | ||||
| 		$user->owner_id = $user->id; | ||||
| 		$user->email = BaseModel::hex($id) . '@example.com'; | ||||
| 		$user->password = '$2y$10$YJeArRNypSbmpWG3RA83n.o78EVlyyVCFN71lWJ7.Omc1VEdwmX5W'; // Session::hashPassword('12345678'); | ||||
| 		$user->save(); | ||||
|  | ||||
| 		return $user; | ||||
| 	} | ||||
|  | ||||
| 	protected function session($userNum = 1, $clientNum = 1, $sessionNum = 1) { | ||||
| 		$userId = $this->createModelId('user', $userNum); | ||||
| 		$clientId = $this->createModelId('client', $clientNum); | ||||
| 		$sessionId = $this->createModelId('session', $sessioNum); | ||||
|  | ||||
| 		$session = Session::find($sessionId); | ||||
| 		if ($session) return $session; | ||||
|  | ||||
| 		$session = new Session(); | ||||
| 		$session->id = $sessionId; | ||||
| 		$session->owner_id = $userId; | ||||
| 		$session->client_id = $clientId; | ||||
| 		$session->save(); | ||||
|  | ||||
| 		return $session; | ||||
| 	} | ||||
|  | ||||
| 	public function setUp() { | ||||
| 		BaseModel::setClientId($this->clientId()); | ||||
| 	} | ||||
|  | ||||
| 	public function tearDown() { | ||||
|  | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										132
									
								
								tests/Model/ChangeTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								tests/Model/ChangeTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,132 @@ | ||||
| <?php | ||||
|  | ||||
| require_once dirname(dirname(__FILE__)) . '/setup.php'; | ||||
|  | ||||
| use AppBundle\Model\BaseModel; | ||||
| use AppBundle\Model\FolderItem; | ||||
| use AppBundle\Model\Note; | ||||
| use AppBundle\Model\Change; | ||||
|  | ||||
| class ChangeTest extends BaseTestCase { | ||||
|  | ||||
| 	public function setUp() { | ||||
| 		parent::setUp(); | ||||
|  | ||||
| 		Change::truncate(); | ||||
| 		Note::truncate(); | ||||
| 	} | ||||
|  | ||||
| 	public function tearDown() { | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	public function testDiff() { | ||||
| 		$text1 = 'abcd efgh ijkl'; | ||||
|  | ||||
| 		$itemId = $this->createModelId('note'); | ||||
|  | ||||
| 		$change = new Change(); | ||||
| 		$change->user_id = $this->user()->id; | ||||
| 		$change->client_id = $this->clientId(); | ||||
| 		$change->item_type = FolderItem::enumId('type', 'note'); | ||||
| 		$change->item_field = BaseModel::enumId('field', 'body'); | ||||
| 		$change->type = Change::enumId('type', 'create'); | ||||
| 		$change->item_id = $itemId; | ||||
| 		$change->createDelta($text1); | ||||
| 		$change->save(); | ||||
| 		 | ||||
| 		$text2 = 'cd efgh NEW ijkl'; | ||||
|  | ||||
| 		$change = new Change(); | ||||
| 		$change->user_id = $this->user()->id; | ||||
| 		$change->client_id = $this->clientId(); | ||||
| 		$change->item_type = FolderItem::enumId('type', 'note'); | ||||
| 		$change->item_field = BaseModel::enumId('field', 'body'); | ||||
| 		$change->type = Change::enumId('type', 'update'); | ||||
| 		$change->item_id = $itemId; | ||||
| 		$change->createDelta($text2); | ||||
| 		$change->save(); | ||||
|  | ||||
| 		$r = Change::fullFieldText($itemId, BaseModel::enumId('field', 'body')); | ||||
|  | ||||
| 		$this->assertEquals($r, $text2); | ||||
| 	} | ||||
|  | ||||
| 	public function testDiff3Ways() { | ||||
| 		// Scenario where two different clients change the same note at the same time. | ||||
| 		// | ||||
| 		// Client 1: 'abcd efgh ijkl' => 'cd efgh ijkl FROMCLIENT2' | ||||
| 		// Client 2: 'abcd efgh ijkl' => 'abcd CLIENT1 efgh ijkl' | ||||
| 		// Expected: 'cd CLIENT1 efgh ijkl FROMCLIENT2' | ||||
|  | ||||
| 		$text1 = 'abcd efgh ijkl'; | ||||
|  | ||||
| 		$itemId = $this->createModelId('note'); | ||||
|  | ||||
| 		$change = new Change(); | ||||
| 		$change->user_id = $this->user()->id; | ||||
| 		$change->client_id = $this->clientId(1); | ||||
| 		$change->item_type = FolderItem::enumId('type', 'note'); | ||||
| 		$change->item_field = BaseModel::enumId('field', 'body'); | ||||
| 		$change->type = Change::enumId('type', 'create'); | ||||
| 		$change->item_id = $itemId; | ||||
| 		$change->createDelta($text1); | ||||
| 		$change->save(); | ||||
|  | ||||
| 		$changeId1 = $change->id; | ||||
| 		 | ||||
| 		$text2 = 'cd efgh ijkl FROMCLIENT2'; | ||||
|  | ||||
| 		$change = new Change(); | ||||
| 		$change->user_id = $this->user()->id; | ||||
| 		$change->client_id = $this->clientId(2); | ||||
| 		$change->item_type = FolderItem::enumId('type', 'note'); | ||||
| 		$change->item_field = BaseModel::enumId('field', 'body'); | ||||
| 		$change->type = Change::enumId('type', 'update'); | ||||
| 		$change->item_id = $itemId; | ||||
| 		$change->previous_id = $changeId1; | ||||
| 		$change->createDelta($text2); | ||||
| 		$change->save(); | ||||
|  | ||||
| 		$changeId2 = $change->id; | ||||
|  | ||||
| 		$text3 = 'abcd CLIENT1 efgh ijkl'; | ||||
|  | ||||
| 		$change = new Change(); | ||||
| 		$change->user_id = $this->user()->id; | ||||
| 		$change->client_id = $this->clientId(1); | ||||
| 		$change->item_type = FolderItem::enumId('type', 'note'); | ||||
| 		$change->item_field = BaseModel::enumId('field', 'body'); | ||||
| 		$change->type = Change::enumId('type', 'update'); | ||||
| 		$change->item_id = $itemId; | ||||
| 		$change->previous_id = $changeId1; | ||||
| 		$change->createDelta($text3); | ||||
| 		$change->save(); | ||||
|  | ||||
| 		$changeId3 = $change->id; | ||||
|  | ||||
| 		$r = Change::fullFieldText($itemId, BaseModel::enumId('field', 'body')); | ||||
|  | ||||
| 		$this->assertEquals($r, 'cd CLIENT1 efgh ijkl FROMCLIENT2'); | ||||
| 	} | ||||
|  | ||||
| 	public function testRevId() { | ||||
| 		$n = new Note(); | ||||
| 		$n->setVersionedFieldValue('body', 'abcd efgh'); | ||||
| 		$n->save(); | ||||
|  | ||||
| 		$noteId = $n->id; | ||||
|  | ||||
| 		$n = Note::find($noteId); | ||||
| 		$d = $n->toPublicArray(); | ||||
| 		$this->assertEquals(1, $d['rev_id']); | ||||
|  | ||||
| 		$n->setVersionedFieldValue('body', '123456'); | ||||
| 		$n->save(); | ||||
|  | ||||
| 		$n = Note::find($noteId); | ||||
| 		$d = $n->toPublicArray(); | ||||
| 		$this->assertEquals(2, $d['rev_id']); | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
							
								
								
									
										42
									
								
								tests/Model/NoteTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								tests/Model/NoteTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| <?php | ||||
|  | ||||
| require_once dirname(dirname(__FILE__)) . '/setup.php'; | ||||
|  | ||||
| use AppBundle\Model\Note; | ||||
|  | ||||
| class NoteTest extends BaseTestCase { | ||||
|  | ||||
| 	public function setUp() { | ||||
| 		parent::setUp(); | ||||
| 	} | ||||
|  | ||||
| 	public function testCanSaveAndLoad() { | ||||
| 		$note = new Note(); | ||||
| 		$note->setVersionedFieldValue('title', 'the title'); | ||||
| 		$note->setVersionedFieldValue('body', 'the body'); | ||||
| 		$note->save(); | ||||
|  | ||||
| 		$note = $note->find($note->id); | ||||
| 		$this->assertNotNull($note); | ||||
| 		$this->assertEquals('the title', $note->versionedFieldValue('title')); | ||||
| 		$this->assertEquals('the body', $note->versionedFieldValue('body')); | ||||
| 	} | ||||
|  | ||||
| 	public function testFromToPublicArray() { | ||||
| 		$a = array( | ||||
| 			'title' => 'the title', | ||||
| 			'body' => 'the body', | ||||
| 		); | ||||
| 		$note = new Note(); | ||||
| 		$note->fromPublicArray($a); | ||||
| 		$note->save(); | ||||
|  | ||||
| 		$note = $note::find($note->id); | ||||
| 		$b = $note->toPublicArray(); | ||||
|  | ||||
| 		$this->assertEquals('the title', $b['title']); | ||||
| 		$this->assertEquals('the body', $b['body']); | ||||
| 		$this->assertArrayHasKey('rev_id', $b); | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
							
								
								
									
										27
									
								
								tests/setup.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								tests/setup.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| <?php | ||||
|  | ||||
| require_once dirname(__FILE__) . '/BaseTestCase.php'; | ||||
|  | ||||
| $dbName = 'notes_test'; | ||||
| $structureFile = dirname(dirname(__FILE__)) . '/structure.sql'; | ||||
|  | ||||
| $cmd = sprintf("mysql -u root -ppass -e 'DROP DATABASE IF EXISTS %s; CREATE DATABASE %s;'", $dbName, $dbName); | ||||
| exec($cmd); | ||||
|  | ||||
| $cmd = sprintf("mysql -u root -ppass %s < '%s'", $dbName, $structureFile); | ||||
| exec($cmd); | ||||
|  | ||||
| $capsule = new \Illuminate\Database\Capsule\Manager(); | ||||
|  | ||||
| $capsule->addConnection([ | ||||
| 	'driver'    => 'mysql', | ||||
| 	'host'      => 'localhost', | ||||
| 	'database'  => 'notes_test', | ||||
| 	'username'  => 'root', | ||||
| 	'password'  => 'pass', | ||||
| 	'charset'   => 'utf8', | ||||
| 	'collation' => 'utf8_unicode_ci', | ||||
| 	'prefix'    => '', | ||||
| ]); | ||||
|  | ||||
| $capsule->bootEloquent(); | ||||
							
								
								
									
										819
									
								
								var/SymfonyRequirements.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										819
									
								
								var/SymfonyRequirements.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,819 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
|  * This file is part of the Symfony package. | ||||
|  * | ||||
|  * (c) Fabien Potencier <fabien@symfony.com> | ||||
|  * | ||||
|  * For the full copyright and license information, please view the LICENSE | ||||
|  * file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Users of PHP 5.2 should be able to run the requirements checks. | ||||
|  * This is why the file and all classes must be compatible with PHP 5.2+ | ||||
|  * (e.g. not using namespaces and closures). | ||||
|  * | ||||
|  * ************** CAUTION ************** | ||||
|  * | ||||
|  * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of | ||||
|  * the installation/update process. The original file resides in the | ||||
|  * SensioDistributionBundle. | ||||
|  * | ||||
|  * ************** CAUTION ************** | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Represents a single PHP requirement, e.g. an installed extension. | ||||
|  * It can be a mandatory requirement or an optional recommendation. | ||||
|  * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration. | ||||
|  * | ||||
|  * @author Tobias Schultze <http://tobion.de> | ||||
|  */ | ||||
| class Requirement | ||||
| { | ||||
|     private $fulfilled; | ||||
|     private $testMessage; | ||||
|     private $helpText; | ||||
|     private $helpHtml; | ||||
|     private $optional; | ||||
|  | ||||
|     /** | ||||
|      * Constructor that initializes the requirement. | ||||
|      * | ||||
|      * @param bool        $fulfilled   Whether the requirement is fulfilled | ||||
|      * @param string      $testMessage The message for testing the requirement | ||||
|      * @param string      $helpHtml    The help text formatted in HTML for resolving the problem | ||||
|      * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) | ||||
|      * @param bool        $optional    Whether this is only an optional recommendation not a mandatory requirement | ||||
|      */ | ||||
|     public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false) | ||||
|     { | ||||
|         $this->fulfilled = (bool) $fulfilled; | ||||
|         $this->testMessage = (string) $testMessage; | ||||
|         $this->helpHtml = (string) $helpHtml; | ||||
|         $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText; | ||||
|         $this->optional = (bool) $optional; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns whether the requirement is fulfilled. | ||||
|      * | ||||
|      * @return bool true if fulfilled, otherwise false | ||||
|      */ | ||||
|     public function isFulfilled() | ||||
|     { | ||||
|         return $this->fulfilled; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the message for testing the requirement. | ||||
|      * | ||||
|      * @return string The test message | ||||
|      */ | ||||
|     public function getTestMessage() | ||||
|     { | ||||
|         return $this->testMessage; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the help text for resolving the problem. | ||||
|      * | ||||
|      * @return string The help text | ||||
|      */ | ||||
|     public function getHelpText() | ||||
|     { | ||||
|         return $this->helpText; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the help text formatted in HTML. | ||||
|      * | ||||
|      * @return string The HTML help | ||||
|      */ | ||||
|     public function getHelpHtml() | ||||
|     { | ||||
|         return $this->helpHtml; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns whether this is only an optional recommendation and not a mandatory requirement. | ||||
|      * | ||||
|      * @return bool true if optional, false if mandatory | ||||
|      */ | ||||
|     public function isOptional() | ||||
|     { | ||||
|         return $this->optional; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Represents a PHP requirement in form of a php.ini configuration. | ||||
|  * | ||||
|  * @author Tobias Schultze <http://tobion.de> | ||||
|  */ | ||||
| class PhpIniRequirement extends Requirement | ||||
| { | ||||
|     /** | ||||
|      * Constructor that initializes the requirement. | ||||
|      * | ||||
|      * @param string        $cfgName           The configuration name used for ini_get() | ||||
|      * @param bool|callback $evaluation        Either a boolean indicating whether the configuration should evaluate to true or false, | ||||
|      *                                         or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement | ||||
|      * @param bool          $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. | ||||
|      *                                         This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. | ||||
|      *                                         Example: You require a config to be true but PHP later removes this config and defaults it to true internally. | ||||
|      * @param string|null   $testMessage       The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) | ||||
|      * @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) | ||||
|      * @param string|null   $helpText          The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) | ||||
|      * @param bool          $optional          Whether this is only an optional recommendation not a mandatory requirement | ||||
|      */ | ||||
|     public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false) | ||||
|     { | ||||
|         $cfgValue = ini_get($cfgName); | ||||
|  | ||||
|         if (is_callable($evaluation)) { | ||||
|             if (null === $testMessage || null === $helpHtml) { | ||||
|                 throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.'); | ||||
|             } | ||||
|  | ||||
|             $fulfilled = call_user_func($evaluation, $cfgValue); | ||||
|         } else { | ||||
|             if (null === $testMessage) { | ||||
|                 $testMessage = sprintf('%s %s be %s in php.ini', | ||||
|                     $cfgName, | ||||
|                     $optional ? 'should' : 'must', | ||||
|                     $evaluation ? 'enabled' : 'disabled' | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
|             if (null === $helpHtml) { | ||||
|                 $helpHtml = sprintf('Set <strong>%s</strong> to <strong>%s</strong> in php.ini<a href="#phpini">*</a>.', | ||||
|                     $cfgName, | ||||
|                     $evaluation ? 'on' : 'off' | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
|             $fulfilled = $evaluation == $cfgValue; | ||||
|         } | ||||
|  | ||||
|         parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * A RequirementCollection represents a set of Requirement instances. | ||||
|  * | ||||
|  * @author Tobias Schultze <http://tobion.de> | ||||
|  */ | ||||
| class RequirementCollection implements IteratorAggregate | ||||
| { | ||||
|     /** | ||||
|      * @var Requirement[] | ||||
|      */ | ||||
|     private $requirements = array(); | ||||
|  | ||||
|     /** | ||||
|      * Gets the current RequirementCollection as an Iterator. | ||||
|      * | ||||
|      * @return Traversable A Traversable interface | ||||
|      */ | ||||
|     public function getIterator() | ||||
|     { | ||||
|         return new ArrayIterator($this->requirements); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds a Requirement. | ||||
|      * | ||||
|      * @param Requirement $requirement A Requirement instance | ||||
|      */ | ||||
|     public function add(Requirement $requirement) | ||||
|     { | ||||
|         $this->requirements[] = $requirement; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds a mandatory requirement. | ||||
|      * | ||||
|      * @param bool        $fulfilled   Whether the requirement is fulfilled | ||||
|      * @param string      $testMessage The message for testing the requirement | ||||
|      * @param string      $helpHtml    The help text formatted in HTML for resolving the problem | ||||
|      * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) | ||||
|      */ | ||||
|     public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null) | ||||
|     { | ||||
|         $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds an optional recommendation. | ||||
|      * | ||||
|      * @param bool        $fulfilled   Whether the recommendation is fulfilled | ||||
|      * @param string      $testMessage The message for testing the recommendation | ||||
|      * @param string      $helpHtml    The help text formatted in HTML for resolving the problem | ||||
|      * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) | ||||
|      */ | ||||
|     public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null) | ||||
|     { | ||||
|         $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds a mandatory requirement in form of a php.ini configuration. | ||||
|      * | ||||
|      * @param string        $cfgName           The configuration name used for ini_get() | ||||
|      * @param bool|callback $evaluation        Either a boolean indicating whether the configuration should evaluate to true or false, | ||||
|      *                                         or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement | ||||
|      * @param bool          $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. | ||||
|      *                                         This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. | ||||
|      *                                         Example: You require a config to be true but PHP later removes this config and defaults it to true internally. | ||||
|      * @param string        $testMessage       The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) | ||||
|      * @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) | ||||
|      * @param string|null   $helpText          The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) | ||||
|      */ | ||||
|     public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) | ||||
|     { | ||||
|         $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds an optional recommendation in form of a php.ini configuration. | ||||
|      * | ||||
|      * @param string        $cfgName           The configuration name used for ini_get() | ||||
|      * @param bool|callback $evaluation        Either a boolean indicating whether the configuration should evaluate to true or false, | ||||
|      *                                         or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement | ||||
|      * @param bool          $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. | ||||
|      *                                         This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. | ||||
|      *                                         Example: You require a config to be true but PHP later removes this config and defaults it to true internally. | ||||
|      * @param string        $testMessage       The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) | ||||
|      * @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) | ||||
|      * @param string|null   $helpText          The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) | ||||
|      */ | ||||
|     public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) | ||||
|     { | ||||
|         $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds a requirement collection to the current set of requirements. | ||||
|      * | ||||
|      * @param RequirementCollection $collection A RequirementCollection instance | ||||
|      */ | ||||
|     public function addCollection(RequirementCollection $collection) | ||||
|     { | ||||
|         $this->requirements = array_merge($this->requirements, $collection->all()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns both requirements and recommendations. | ||||
|      * | ||||
|      * @return Requirement[] | ||||
|      */ | ||||
|     public function all() | ||||
|     { | ||||
|         return $this->requirements; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns all mandatory requirements. | ||||
|      * | ||||
|      * @return Requirement[] | ||||
|      */ | ||||
|     public function getRequirements() | ||||
|     { | ||||
|         $array = array(); | ||||
|         foreach ($this->requirements as $req) { | ||||
|             if (!$req->isOptional()) { | ||||
|                 $array[] = $req; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $array; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the mandatory requirements that were not met. | ||||
|      * | ||||
|      * @return Requirement[] | ||||
|      */ | ||||
|     public function getFailedRequirements() | ||||
|     { | ||||
|         $array = array(); | ||||
|         foreach ($this->requirements as $req) { | ||||
|             if (!$req->isFulfilled() && !$req->isOptional()) { | ||||
|                 $array[] = $req; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $array; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns all optional recommendations. | ||||
|      * | ||||
|      * @return Requirement[] | ||||
|      */ | ||||
|     public function getRecommendations() | ||||
|     { | ||||
|         $array = array(); | ||||
|         foreach ($this->requirements as $req) { | ||||
|             if ($req->isOptional()) { | ||||
|                 $array[] = $req; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $array; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the recommendations that were not met. | ||||
|      * | ||||
|      * @return Requirement[] | ||||
|      */ | ||||
|     public function getFailedRecommendations() | ||||
|     { | ||||
|         $array = array(); | ||||
|         foreach ($this->requirements as $req) { | ||||
|             if (!$req->isFulfilled() && $req->isOptional()) { | ||||
|                 $array[] = $req; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $array; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns whether a php.ini configuration is not correct. | ||||
|      * | ||||
|      * @return bool php.ini configuration problem? | ||||
|      */ | ||||
|     public function hasPhpIniConfigIssue() | ||||
|     { | ||||
|         foreach ($this->requirements as $req) { | ||||
|             if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the PHP configuration file (php.ini) path. | ||||
|      * | ||||
|      * @return string|false php.ini file path | ||||
|      */ | ||||
|     public function getPhpIniConfigPath() | ||||
|     { | ||||
|         return get_cfg_var('cfg_file_path'); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This class specifies all requirements and optional recommendations that | ||||
|  * are necessary to run the Symfony Standard Edition. | ||||
|  * | ||||
|  * @author Tobias Schultze <http://tobion.de> | ||||
|  * @author Fabien Potencier <fabien@symfony.com> | ||||
|  */ | ||||
| class SymfonyRequirements extends RequirementCollection | ||||
| { | ||||
|     const LEGACY_REQUIRED_PHP_VERSION = '5.3.3'; | ||||
|     const REQUIRED_PHP_VERSION = '5.5.9'; | ||||
|  | ||||
|     /** | ||||
|      * Constructor that initializes the requirements. | ||||
|      */ | ||||
|     public function __construct() | ||||
|     { | ||||
|         /* mandatory requirements follow */ | ||||
|  | ||||
|         $installedPhpVersion = phpversion(); | ||||
|         $requiredPhpVersion = $this->getPhpRequiredVersion(); | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             $requiredPhpVersion, | ||||
|             'Vendors should be installed in order to check all requirements.', | ||||
|             'Run the <code>composer install</code> command.', | ||||
|             'Run the "composer install" command.' | ||||
|         ); | ||||
|  | ||||
|         if (false !== $requiredPhpVersion) { | ||||
|             $this->addRequirement( | ||||
|                 version_compare($installedPhpVersion, $requiredPhpVersion, '>='), | ||||
|                 sprintf('PHP version must be at least %s (%s installed)', $requiredPhpVersion, $installedPhpVersion), | ||||
|                 sprintf('You are running PHP version "<strong>%s</strong>", but Symfony needs at least PHP "<strong>%s</strong>" to run. | ||||
|                 Before using Symfony, upgrade your PHP installation, preferably to the latest version.', | ||||
|                     $installedPhpVersion, $requiredPhpVersion), | ||||
|                 sprintf('Install PHP %s or newer (installed version is %s)', $requiredPhpVersion, $installedPhpVersion) | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             version_compare($installedPhpVersion, '5.3.16', '!='), | ||||
|             'PHP version must not be 5.3.16 as Symfony won\'t work properly with it', | ||||
|             'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)' | ||||
|         ); | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             is_dir(__DIR__.'/../vendor/composer'), | ||||
|             'Vendor libraries must be installed', | ||||
|             'Vendor libraries are missing. Install composer following instructions from <a href="http://getcomposer.org/">http://getcomposer.org/</a>. '. | ||||
|                 'Then run "<strong>php composer.phar install</strong>" to install them.' | ||||
|         ); | ||||
|  | ||||
|         $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache'; | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             is_writable($cacheDir), | ||||
|             'app/cache/ or var/cache/ directory must be writable', | ||||
|             'Change the permissions of either "<strong>app/cache/</strong>" or  "<strong>var/cache/</strong>" directory so that the web server can write into it.' | ||||
|         ); | ||||
|  | ||||
|         $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs'; | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             is_writable($logsDir), | ||||
|             'app/logs/ or var/logs/ directory must be writable', | ||||
|             'Change the permissions of either "<strong>app/logs/</strong>" or  "<strong>var/logs/</strong>" directory so that the web server can write into it.' | ||||
|         ); | ||||
|  | ||||
|         if (version_compare($installedPhpVersion, '7.0.0', '<')) { | ||||
|             $this->addPhpIniRequirement( | ||||
|                 'date.timezone', true, false, | ||||
|                 'date.timezone setting must be set', | ||||
|                 'Set the "<strong>date.timezone</strong>" setting in php.ini<a href="#phpini">*</a> (like Europe/Paris).' | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         if (false !== $requiredPhpVersion && version_compare($installedPhpVersion, $requiredPhpVersion, '>=')) { | ||||
|             $timezones = array(); | ||||
|             foreach (DateTimeZone::listAbbreviations() as $abbreviations) { | ||||
|                 foreach ($abbreviations as $abbreviation) { | ||||
|                     $timezones[$abbreviation['timezone_id']] = true; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             $this->addRequirement( | ||||
|                 isset($timezones[@date_default_timezone_get()]), | ||||
|                 sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()), | ||||
|                 'Your default timezone is not supported by PHP. Check for typos in your <strong>php.ini</strong> file and have a look at the list of deprecated timezones at <a href="http://php.net/manual/en/timezones.others.php">http://php.net/manual/en/timezones.others.php</a>.' | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             function_exists('iconv'), | ||||
|             'iconv() must be available', | ||||
|             'Install and enable the <strong>iconv</strong> extension.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             function_exists('json_encode'), | ||||
|             'json_encode() must be available', | ||||
|             'Install and enable the <strong>JSON</strong> extension.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             function_exists('session_start'), | ||||
|             'session_start() must be available', | ||||
|             'Install and enable the <strong>session</strong> extension.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             function_exists('ctype_alpha'), | ||||
|             'ctype_alpha() must be available', | ||||
|             'Install and enable the <strong>ctype</strong> extension.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             function_exists('token_get_all'), | ||||
|             'token_get_all() must be available', | ||||
|             'Install and enable the <strong>Tokenizer</strong> extension.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             function_exists('simplexml_import_dom'), | ||||
|             'simplexml_import_dom() must be available', | ||||
|             'Install and enable the <strong>SimpleXML</strong> extension.' | ||||
|         ); | ||||
|  | ||||
|         if (function_exists('apc_store') && ini_get('apc.enabled')) { | ||||
|             if (version_compare($installedPhpVersion, '5.4.0', '>=')) { | ||||
|                 $this->addRequirement( | ||||
|                     version_compare(phpversion('apc'), '3.1.13', '>='), | ||||
|                     'APC version must be at least 3.1.13 when using PHP 5.4', | ||||
|                     'Upgrade your <strong>APC</strong> extension (3.1.13+).' | ||||
|                 ); | ||||
|             } else { | ||||
|                 $this->addRequirement( | ||||
|                     version_compare(phpversion('apc'), '3.0.17', '>='), | ||||
|                     'APC version must be at least 3.0.17', | ||||
|                     'Upgrade your <strong>APC</strong> extension (3.0.17+).' | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $this->addPhpIniRequirement('detect_unicode', false); | ||||
|  | ||||
|         if (extension_loaded('suhosin')) { | ||||
|             $this->addPhpIniRequirement( | ||||
|                 'suhosin.executor.include.whitelist', | ||||
|                 create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'), | ||||
|                 false, | ||||
|                 'suhosin.executor.include.whitelist must be configured correctly in php.ini', | ||||
|                 'Add "<strong>phar</strong>" to <strong>suhosin.executor.include.whitelist</strong> in php.ini<a href="#phpini">*</a>.' | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         if (extension_loaded('xdebug')) { | ||||
|             $this->addPhpIniRequirement( | ||||
|                 'xdebug.show_exception_trace', false, true | ||||
|             ); | ||||
|  | ||||
|             $this->addPhpIniRequirement( | ||||
|                 'xdebug.scream', false, true | ||||
|             ); | ||||
|  | ||||
|             $this->addPhpIniRecommendation( | ||||
|                 'xdebug.max_nesting_level', | ||||
|                 create_function('$cfgValue', 'return $cfgValue > 100;'), | ||||
|                 true, | ||||
|                 'xdebug.max_nesting_level should be above 100 in php.ini', | ||||
|                 'Set "<strong>xdebug.max_nesting_level</strong>" to e.g. "<strong>250</strong>" in php.ini<a href="#phpini">*</a> to stop Xdebug\'s infinite recursion protection erroneously throwing a fatal error in your project.' | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null; | ||||
|  | ||||
|         $this->addRequirement( | ||||
|             null !== $pcreVersion, | ||||
|             'PCRE extension must be available', | ||||
|             'Install the <strong>PCRE</strong> extension (version 8.0+).' | ||||
|         ); | ||||
|  | ||||
|         if (extension_loaded('mbstring')) { | ||||
|             $this->addPhpIniRequirement( | ||||
|                 'mbstring.func_overload', | ||||
|                 create_function('$cfgValue', 'return (int) $cfgValue === 0;'), | ||||
|                 true, | ||||
|                 'string functions should not be overloaded', | ||||
|                 'Set "<strong>mbstring.func_overload</strong>" to <strong>0</strong> in php.ini<a href="#phpini">*</a> to disable function overloading by the mbstring extension.' | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         /* optional recommendations follow */ | ||||
|  | ||||
|         if (file_exists(__DIR__.'/../vendor/composer')) { | ||||
|             require_once __DIR__.'/../vendor/autoload.php'; | ||||
|  | ||||
|             try { | ||||
|                 $r = new ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle'); | ||||
|  | ||||
|                 $contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php'); | ||||
|             } catch (ReflectionException $e) { | ||||
|                 $contents = ''; | ||||
|             } | ||||
|             $this->addRecommendation( | ||||
|                 file_get_contents(__FILE__) === $contents, | ||||
|                 'Requirements file should be up-to-date', | ||||
|                 'Your requirements file is outdated. Run composer install and re-check your configuration.' | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             version_compare($installedPhpVersion, '5.3.4', '>='), | ||||
|             'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions', | ||||
|             '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.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             version_compare($installedPhpVersion, '5.3.8', '>='), | ||||
|             'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156', | ||||
|             'Install PHP 5.3.8 or newer if your project uses annotations.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             version_compare($installedPhpVersion, '5.4.0', '!='), | ||||
|             'You should not use PHP 5.4.0 due to the PHP bug #61453', | ||||
|             '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.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             version_compare($installedPhpVersion, '5.4.11', '>='), | ||||
|             '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)', | ||||
|             'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<')) | ||||
|             || | ||||
|             version_compare($installedPhpVersion, '5.4.8', '>='), | ||||
|             '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', | ||||
|             'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.' | ||||
|         ); | ||||
|  | ||||
|         if (null !== $pcreVersion) { | ||||
|             $this->addRecommendation( | ||||
|                 $pcreVersion >= 8.0, | ||||
|                 sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion), | ||||
|                 '<strong>PCRE 8.0+</strong> 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.' | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             class_exists('DomDocument'), | ||||
|             'PHP-DOM and PHP-XML modules should be installed', | ||||
|             'Install and enable the <strong>PHP-DOM</strong> and the <strong>PHP-XML</strong> modules.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             function_exists('mb_strlen'), | ||||
|             'mb_strlen() should be available', | ||||
|             'Install and enable the <strong>mbstring</strong> extension.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             function_exists('iconv'), | ||||
|             'iconv() should be available', | ||||
|             'Install and enable the <strong>iconv</strong> extension.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             function_exists('utf8_decode'), | ||||
|             'utf8_decode() should be available', | ||||
|             'Install and enable the <strong>XML</strong> extension.' | ||||
|         ); | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             function_exists('filter_var'), | ||||
|             'filter_var() should be available', | ||||
|             'Install and enable the <strong>filter</strong> extension.' | ||||
|         ); | ||||
|  | ||||
|         if (!defined('PHP_WINDOWS_VERSION_BUILD')) { | ||||
|             $this->addRecommendation( | ||||
|                 function_exists('posix_isatty'), | ||||
|                 'posix_isatty() should be available', | ||||
|                 'Install and enable the <strong>php_posix</strong> extension (used to colorize the CLI output).' | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             extension_loaded('intl'), | ||||
|             'intl extension should be available', | ||||
|             'Install and enable the <strong>intl</strong> extension (used for validators).' | ||||
|         ); | ||||
|  | ||||
|         if (extension_loaded('intl')) { | ||||
|             // in some WAMP server installations, new Collator() returns null | ||||
|             $this->addRecommendation( | ||||
|                 null !== new Collator('fr_FR'), | ||||
|                 'intl extension should be correctly configured', | ||||
|                 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.' | ||||
|             ); | ||||
|  | ||||
|             // check for compatible ICU versions (only done when you have the intl extension) | ||||
|             if (defined('INTL_ICU_VERSION')) { | ||||
|                 $version = INTL_ICU_VERSION; | ||||
|             } else { | ||||
|                 $reflector = new ReflectionExtension('intl'); | ||||
|  | ||||
|                 ob_start(); | ||||
|                 $reflector->info(); | ||||
|                 $output = strip_tags(ob_get_clean()); | ||||
|  | ||||
|                 preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches); | ||||
|                 $version = $matches[1]; | ||||
|             } | ||||
|  | ||||
|             $this->addRecommendation( | ||||
|                 version_compare($version, '4.0', '>='), | ||||
|                 'intl ICU version should be at least 4+', | ||||
|                 'Upgrade your <strong>intl</strong> extension with a newer ICU version (4+).' | ||||
|             ); | ||||
|  | ||||
|             if (class_exists('Symfony\Component\Intl\Intl')) { | ||||
|                 $this->addRecommendation( | ||||
|                     \Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion(), | ||||
|                     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()), | ||||
|                     'To get the latest internationalization data upgrade the ICU system package and the intl PHP extension.' | ||||
|                 ); | ||||
|                 if (\Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion()) { | ||||
|                     $this->addRecommendation( | ||||
|                         \Symfony\Component\Intl\Intl::getIcuDataVersion() === \Symfony\Component\Intl\Intl::getIcuVersion(), | ||||
|                         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()), | ||||
|                         'To avoid internationalization data inconsistencies upgrade the symfony/intl component.' | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             $this->addPhpIniRecommendation( | ||||
|                 'intl.error_level', | ||||
|                 create_function('$cfgValue', 'return (int) $cfgValue === 0;'), | ||||
|                 true, | ||||
|                 'intl.error_level should be 0 in php.ini', | ||||
|                 'Set "<strong>intl.error_level</strong>" to "<strong>0</strong>" in php.ini<a href="#phpini">*</a> to inhibit the messages when an error occurs in ICU functions.' | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $accelerator = | ||||
|             (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) | ||||
|             || | ||||
|             (extension_loaded('apc') && ini_get('apc.enabled')) | ||||
|             || | ||||
|             (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable')) | ||||
|             || | ||||
|             (extension_loaded('Zend OPcache') && ini_get('opcache.enable')) | ||||
|             || | ||||
|             (extension_loaded('xcache') && ini_get('xcache.cacher')) | ||||
|             || | ||||
|             (extension_loaded('wincache') && ini_get('wincache.ocenabled')) | ||||
|         ; | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             $accelerator, | ||||
|             'a PHP accelerator should be installed', | ||||
|             'Install and/or enable a <strong>PHP accelerator</strong> (highly recommended).' | ||||
|         ); | ||||
|  | ||||
|         if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { | ||||
|             $this->addRecommendation( | ||||
|                 $this->getRealpathCacheSize() >= 5 * 1024 * 1024, | ||||
|                 'realpath_cache_size should be at least 5M in php.ini', | ||||
|                 'Setting "<strong>realpath_cache_size</strong>" to e.g. "<strong>5242880</strong>" or "<strong>5M</strong>" in php.ini<a href="#phpini">*</a> may improve performance on Windows significantly in some cases.' | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $this->addPhpIniRecommendation('short_open_tag', false); | ||||
|  | ||||
|         $this->addPhpIniRecommendation('magic_quotes_gpc', false, true); | ||||
|  | ||||
|         $this->addPhpIniRecommendation('register_globals', false, true); | ||||
|  | ||||
|         $this->addPhpIniRecommendation('session.auto_start', false); | ||||
|  | ||||
|         $this->addRecommendation( | ||||
|             class_exists('PDO'), | ||||
|             'PDO should be installed', | ||||
|             'Install <strong>PDO</strong> (mandatory for Doctrine).' | ||||
|         ); | ||||
|  | ||||
|         if (class_exists('PDO')) { | ||||
|             $drivers = PDO::getAvailableDrivers(); | ||||
|             $this->addRecommendation( | ||||
|                 count($drivers) > 0, | ||||
|                 sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'), | ||||
|                 'Install <strong>PDO drivers</strong> (mandatory for Doctrine).' | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Loads realpath_cache_size from php.ini and converts it to int. | ||||
|      * | ||||
|      * (e.g. 16k is converted to 16384 int) | ||||
|      * | ||||
|      * @return int | ||||
|      */ | ||||
|     protected function getRealpathCacheSize() | ||||
|     { | ||||
|         $size = ini_get('realpath_cache_size'); | ||||
|         $size = trim($size); | ||||
|         $unit = strtolower(substr($size, -1, 1)); | ||||
|         switch ($unit) { | ||||
|             case 'g': | ||||
|                 return $size * 1024 * 1024 * 1024; | ||||
|             case 'm': | ||||
|                 return $size * 1024 * 1024; | ||||
|             case 'k': | ||||
|                 return $size * 1024; | ||||
|             default: | ||||
|                 return (int) $size; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Defines PHP required version from Symfony version. | ||||
|      * | ||||
|      * @return string|false The PHP required version or false if it could not be guessed | ||||
|      */ | ||||
|     protected function getPhpRequiredVersion() | ||||
|     { | ||||
|         if (!file_exists($path = __DIR__.'/../composer.lock')) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $composerLock = json_decode(file_get_contents($path), true); | ||||
|         foreach ($composerLock['packages'] as $package) { | ||||
|             $name = $package['name']; | ||||
|             if ('symfony/symfony' !== $name && 'symfony/http-kernel' !== $name) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             return (int) $package['version'][1] > 2 ? self::REQUIRED_PHP_VERSION : self::LEGACY_REQUIRED_PHP_VERSION; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										0
									
								
								var/cache/.gitkeep
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								var/cache/.gitkeep
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								var/logs/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								var/logs/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								var/sessions/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								var/sessions/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										68
									
								
								web/.htaccess
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								web/.htaccess
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| # Use the front controller as index file. It serves as a fallback solution when | ||||
| # every other rewrite/redirect fails (e.g. in an aliased environment without | ||||
| # mod_rewrite). Additionally, this reduces the matching process for the | ||||
| # start page (path "/") because otherwise Apache will apply the rewriting rules | ||||
| # to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl). | ||||
| DirectoryIndex app.php | ||||
|  | ||||
| # By default, Apache does not evaluate symbolic links if you did not enable this | ||||
| # feature in your server configuration. Uncomment the following line if you | ||||
| # install assets as symlinks or if you experience problems related to symlinks | ||||
| # when compiling LESS/Sass/CoffeScript assets. | ||||
| # Options FollowSymlinks | ||||
|  | ||||
| # Disabling MultiViews prevents unwanted negotiation, e.g. "/app" should not resolve | ||||
| # to the front controller "/app.php" but be rewritten to "/app.php/app". | ||||
| <IfModule mod_negotiation.c> | ||||
|     Options -MultiViews | ||||
| </IfModule> | ||||
|  | ||||
| <IfModule mod_rewrite.c> | ||||
|     RewriteEngine On | ||||
|  | ||||
|     # Determine the RewriteBase automatically and set it as environment variable. | ||||
|     # If you are using Apache aliases to do mass virtual hosting or installed the | ||||
|     # project in a subdirectory, the base path will be prepended to allow proper | ||||
|     # resolution of the app.php file and to redirect to the correct URI. It will | ||||
|     # work in environments without path prefix as well, providing a safe, one-size | ||||
|     # fits all solution. But as you do not need it in this case, you can comment | ||||
|     # the following 2 lines to eliminate the overhead. | ||||
|     RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ | ||||
|     RewriteRule ^(.*) - [E=BASE:%1] | ||||
|  | ||||
|     # Sets the HTTP_AUTHORIZATION header removed by Apache | ||||
|     RewriteCond %{HTTP:Authorization} . | ||||
|     RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] | ||||
|  | ||||
|     # Redirect to URI without front controller to prevent duplicate content | ||||
|     # (with and without `/app.php`). Only do this redirect on the initial | ||||
|     # rewrite by Apache and not on subsequent cycles. Otherwise we would get an | ||||
|     # endless redirect loop (request -> rewrite to front controller -> | ||||
|     # redirect -> request -> ...). | ||||
|     # So in case you get a "too many redirects" error or you always get redirected | ||||
|     # to the start page because your Apache does not expose the REDIRECT_STATUS | ||||
|     # environment variable, you have 2 choices: | ||||
|     # - disable this feature by commenting the following 2 lines or | ||||
|     # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the | ||||
|     #   following RewriteCond (best solution) | ||||
|     RewriteCond %{ENV:REDIRECT_STATUS} ^$ | ||||
|     RewriteRule ^app\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L] | ||||
|  | ||||
|     # If the requested filename exists, simply serve it. | ||||
|     # We only want to let Apache serve files and not directories. | ||||
|     RewriteCond %{REQUEST_FILENAME} -f | ||||
|     RewriteRule ^ - [L] | ||||
|  | ||||
|     # Rewrite all other queries to the front controller. | ||||
|     RewriteRule ^ %{ENV:BASE}/app.php [L] | ||||
| </IfModule> | ||||
|  | ||||
| <IfModule !mod_rewrite.c> | ||||
|     <IfModule mod_alias.c> | ||||
|         # When mod_rewrite is not available, we instruct a temporary redirect of | ||||
|         # the start page to the front controller explicitly so that the website | ||||
|         # and the generated links can still be used. | ||||
|         RedirectMatch 302 ^/$ /app.php/ | ||||
|         # RedirectTemp cannot be used instead | ||||
|     </IfModule> | ||||
| </IfModule> | ||||
							
								
								
									
										18
									
								
								web/app.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								web/app.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| <?php | ||||
|  | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
|  | ||||
| /** @var \Composer\Autoload\ClassLoader $loader */ | ||||
| $loader = require __DIR__.'/../app/autoload.php'; | ||||
| include_once __DIR__.'/../var/bootstrap.php.cache'; | ||||
|  | ||||
| $kernel = new AppKernel('prod', false); | ||||
| $kernel->loadClassCache(); | ||||
| //$kernel = new AppCache($kernel); | ||||
|  | ||||
| // When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter | ||||
| //Request::enableHttpMethodParameterOverride(); | ||||
| $request = Request::createFromGlobals(); | ||||
| $response = $kernel->handle($request); | ||||
| $response->send(); | ||||
| $kernel->terminate($request, $response); | ||||
							
								
								
									
										40
									
								
								web/app_dev.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								web/app_dev.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| <?php | ||||
|  | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| // use Symfony\Component\Debug\Debug; | ||||
|  | ||||
| // If you don't want to setup permissions the proper way, just uncomment the following PHP line | ||||
| // read http://symfony.com/doc/current/book/installation.html#checking-symfony-application-configuration-and-setup | ||||
| // for more information | ||||
| //umask(0000); | ||||
|  | ||||
| // This check prevents access to debug front controllers that are deployed by accident to production servers. | ||||
| // Feel free to remove this, extend it, or make something more sophisticated. | ||||
| if (isset($_SERVER['HTTP_CLIENT_IP']) | ||||
|     || isset($_SERVER['HTTP_X_FORWARDED_FOR']) | ||||
|     || !(in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1']) || php_sapi_name() === 'cli-server') | ||||
| ) { | ||||
|     header('HTTP/1.0 403 Forbidden'); | ||||
|     exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.'); | ||||
| } | ||||
|  | ||||
| /** @var \Composer\Autoload\ClassLoader $loader */ | ||||
| $loader = require __DIR__.'/../app/autoload.php'; | ||||
|  | ||||
| // Disable error handling page: | ||||
| // Debug::enable(); | ||||
|  | ||||
| set_exception_handler(function($e) { | ||||
| 	$msg = array(); | ||||
| 	$msg[] = 'Exception: ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine(); | ||||
| 	$msg[] = ''; | ||||
| 	$msg[] = $e->getTraceAsString(); | ||||
| 	echo implode("\n", $msg); | ||||
| }); | ||||
|  | ||||
| $kernel = new AppKernel('dev', true); | ||||
| $kernel->loadClassCache(); | ||||
| $request = Request::createFromGlobals(); | ||||
| $response = $kernel->handle($request); | ||||
| $response->send(); | ||||
| $kernel->terminate($request, $response); | ||||
							
								
								
									
										
											BIN
										
									
								
								web/apple-touch-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/apple-touch-icon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 2.0 KiB | 
							
								
								
									
										422
									
								
								web/config.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										422
									
								
								web/config.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,422 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
|  * ************** CAUTION ************** | ||||
|  * | ||||
|  * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of | ||||
|  * the installation/update process. The original file resides in the | ||||
|  * SensioDistributionBundle. | ||||
|  * | ||||
|  * ************** CAUTION ************** | ||||
|  */ | ||||
|  | ||||
| if (!isset($_SERVER['HTTP_HOST'])) { | ||||
|     exit('This script cannot be run from the CLI. Run it from a browser.'); | ||||
| } | ||||
|  | ||||
| if (!in_array(@$_SERVER['REMOTE_ADDR'], array( | ||||
|     '127.0.0.1', | ||||
|     '::1', | ||||
| ))) { | ||||
|     header('HTTP/1.0 403 Forbidden'); | ||||
|     exit('This script is only accessible from localhost.'); | ||||
| } | ||||
|  | ||||
| require_once dirname(__FILE__).'/../var/SymfonyRequirements.php'; | ||||
|  | ||||
| $symfonyRequirements = new SymfonyRequirements(); | ||||
|  | ||||
| $majorProblems = $symfonyRequirements->getFailedRequirements(); | ||||
| $minorProblems = $symfonyRequirements->getFailedRecommendations(); | ||||
| $hasMajorProblems = (bool) count($majorProblems); | ||||
| $hasMinorProblems = (bool) count($minorProblems); | ||||
|  | ||||
| ?> | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | ||||
|         <meta name="robots" content="noindex,nofollow" /> | ||||
|         <title>Symfony Configuration Checker</title> | ||||
|         <style> | ||||
|             /* styles copied from symfony framework bundle */ | ||||
|             html { | ||||
|                 background: #eee; | ||||
|             } | ||||
|             body { | ||||
|                 font: 11px Verdana, Arial, sans-serif; | ||||
|                 color: #333; | ||||
|             } | ||||
|             .sf-reset, .sf-reset .block, .sf-reset #message { | ||||
|                 margin: auto; | ||||
|             } | ||||
|             img { | ||||
|                 border: 0; | ||||
|             } | ||||
|             .clear { | ||||
|                 clear: both; | ||||
|                 height: 0; | ||||
|                 font-size: 0; | ||||
|                 line-height: 0; | ||||
|             } | ||||
|             .clear-fix:after { | ||||
|                 content: "\0020"; | ||||
|                 display: block; | ||||
|                 height: 0; | ||||
|                 clear: both; | ||||
|                 visibility: hidden; | ||||
|             } | ||||
|             .clear-fix { | ||||
|                 display: inline-block; | ||||
|             } | ||||
|             * html .clear-fix { | ||||
|                 height: 1%; | ||||
|             } | ||||
|             .clear-fix { | ||||
|                 display: block; | ||||
|             } | ||||
|             .header { | ||||
|                 padding: 30px 30px 20px 30px; | ||||
|             } | ||||
|             .header-logo { | ||||
|                 float: left; | ||||
|             } | ||||
|             .search { | ||||
|                 float: right; | ||||
|                 padding-top: 20px; | ||||
|             } | ||||
|             .search label { | ||||
|                 line-height: 28px; | ||||
|                 vertical-align: middle; | ||||
|             } | ||||
|             .search input { | ||||
|                 width: 195px; | ||||
|                 font-size: 12px; | ||||
|                 border: 1px solid #dadada; | ||||
|                 background: #fff url(data:image/gif;base64,R0lGODlhAQAFAKIAAPX19e/v7/39/fr6+urq6gAAAAAAAAAAACH5BAAAAAAALAAAAAABAAUAAAMESAEjCQA7) repeat-x left top; | ||||
|                 padding: 5px 6px; | ||||
|                 color: #565656; | ||||
|             } | ||||
|             .search input[type="search"] { | ||||
|                 -webkit-appearance: textfield; | ||||
|             } | ||||
|             #content { | ||||
|                 width: 970px; | ||||
|                 margin: 0 auto; | ||||
|             } | ||||
|             #content pre { | ||||
|                 white-space: normal; | ||||
|                 font-family: Arial, Helvetica, sans-serif; | ||||
|             } | ||||
|  | ||||
|             /* | ||||
|             Copyright (c) 2010, Yahoo! Inc. All rights reserved. | ||||
|             Code licensed under the BSD License: | ||||
|             http://developer.yahoo.com/yui/license.html | ||||
|             version: 3.1.2 | ||||
|             build: 56 | ||||
|             */ | ||||
|             .sf-reset div,.sf-reset dl,.sf-reset dt,.sf-reset dd,.sf-reset ul,.sf-reset ol,.sf-reset li,.sf-reset h1,.sf-reset h2,.sf-reset h3,.sf-reset h4,.sf-reset h5,.sf-reset h6,.sf-reset pre,.sf-reset code,.sf-reset form,.sf-reset fieldset,.sf-reset legend,.sf-reset input,.sf-reset textarea,.sf-reset p,.sf-reset blockquote,.sf-reset th,.sf-reset td{margin:0;padding:0;}.sf-reset table{border-collapse:collapse;border-spacing:0;}.sf-reset fieldset,.sf-reset img{border:0;}.sf-reset address,.sf-reset caption,.sf-reset cite,.sf-reset code,.sf-reset dfn,.sf-reset em,.sf-reset strong,.sf-reset th,.sf-reset var{font-style:normal;font-weight:normal;}.sf-reset li{list-style:none;}.sf-reset caption,.sf-reset th{text-align:left;}.sf-reset h1,.sf-reset h2,.sf-reset h3,.sf-reset h4,.sf-reset h5,.sf-reset h6{font-size:100%;font-weight:normal;}.sf-reset q:before,.sf-reset q:after{content:'';}.sf-reset abbr,.sf-reset acronym{border:0;font-variant:normal;}.sf-reset sup{vertical-align:text-top;}.sf-reset sub{vertical-align:text-bottom;}.sf-reset input,.sf-reset textarea,.sf-reset select{font-family:inherit;font-size:inherit;font-weight:inherit;}.sf-reset input,.sf-reset textarea,.sf-reset select{font-size:100%;}.sf-reset legend{color:#000;} | ||||
|             .sf-reset abbr { | ||||
|                 border-bottom: 1px dotted #000; | ||||
|                 cursor: help; | ||||
|             } | ||||
|             .sf-reset p { | ||||
|                 font-size: 14px; | ||||
|                 line-height: 20px; | ||||
|                 padding-bottom: 20px; | ||||
|             } | ||||
|             .sf-reset strong { | ||||
|                 color: #313131; | ||||
|                 font-weight: bold; | ||||
|             } | ||||
|             .sf-reset a { | ||||
|                 color: #6c6159; | ||||
|             } | ||||
|             .sf-reset a img { | ||||
|                 border: none; | ||||
|             } | ||||
|             .sf-reset a:hover { | ||||
|                 text-decoration: underline; | ||||
|             } | ||||
|             .sf-reset em { | ||||
|                 font-style: italic; | ||||
|             } | ||||
|             .sf-reset h2, | ||||
|             .sf-reset h3 { | ||||
|                 font-weight: bold; | ||||
|             } | ||||
|             .sf-reset h1 { | ||||
|                 font-family: Georgia, "Times New Roman", Times, serif; | ||||
|                 font-size: 20px; | ||||
|                 color: #313131; | ||||
|                 word-wrap: break-word; | ||||
|             } | ||||
|             .sf-reset li { | ||||
|                 padding-bottom: 10px; | ||||
|             } | ||||
|             .sf-reset .block { | ||||
|                 -moz-border-radius: 16px; | ||||
|                 -webkit-border-radius: 16px; | ||||
|                 border-radius: 16px; | ||||
|                 margin-bottom: 20px; | ||||
|                 background-color: #FFFFFF; | ||||
|                 border: 1px solid #dfdfdf; | ||||
|                 padding: 40px 50px; | ||||
|                 word-break: break-all; | ||||
|             } | ||||
|             .sf-reset h2 { | ||||
|                 font-size: 16px; | ||||
|                 font-family: Arial, Helvetica, sans-serif; | ||||
|             } | ||||
|             .sf-reset li a { | ||||
|                 background: none; | ||||
|                 color: #868686; | ||||
|                 text-decoration: none; | ||||
|             } | ||||
|             .sf-reset li a:hover { | ||||
|                 background: none; | ||||
|                 color: #313131; | ||||
|                 text-decoration: underline; | ||||
|             } | ||||
|             .sf-reset ol { | ||||
|                 padding: 10px 0; | ||||
|             } | ||||
|             .sf-reset ol li { | ||||
|                 list-style: decimal; | ||||
|                 margin-left: 20px; | ||||
|                 padding: 2px; | ||||
|                 padding-bottom: 20px; | ||||
|             } | ||||
|             .sf-reset ol ol li { | ||||
|                 list-style-position: inside; | ||||
|                 margin-left: 0; | ||||
|                 white-space: nowrap; | ||||
|                 font-size: 12px; | ||||
|                 padding-bottom: 0; | ||||
|             } | ||||
|             .sf-reset li .selected { | ||||
|                 background-color: #ffd; | ||||
|             } | ||||
|             .sf-button { | ||||
|                 display: -moz-inline-box; | ||||
|                 display: inline-block; | ||||
|                 text-align: center; | ||||
|                 vertical-align: middle; | ||||
|                 border: 0; | ||||
|                 background: transparent none; | ||||
|                 text-transform: uppercase; | ||||
|                 cursor: pointer; | ||||
|                 font: bold 11px Arial, Helvetica, sans-serif; | ||||
|             } | ||||
|             .sf-button span { | ||||
|                 text-decoration: none; | ||||
|                 display: block; | ||||
|                 height: 28px; | ||||
|                 float: left; | ||||
|             } | ||||
|             .sf-button .border-l { | ||||
|                 text-decoration: none; | ||||
|                 display: block; | ||||
|                 height: 28px; | ||||
|                 float: left; | ||||
|                 padding: 0 0 0 7px; | ||||
|                 background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAcCAYAAACtQ6WLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQtJREFUeNpiPHnyJAMakARiByDWYEGT8ADiYGVlZStubm5xlv///4MEQYoKZGRkQkRERLRYWVl5wYJQyXBZWdkwCQkJUxAHKgaWlAHSLqKiosb//v1DsYMFKGCvoqJiDmQzwXTAJYECulxcXNLoumCSoszMzDzoumDGghQwYZUECWIzkrAkSIIGOmlkLI10AiX//P379x8jIyMTNmPf/v79+ysLCwsvuiQoNi5//fr1Kch4dAyS3P/gwYMTQBP+wxwHw0xA4gkQ73v9+vUZdJ2w1Lf82bNn4iCHCQoKasHsZw4ODgbRIL8c+/Lly5M3b978Y2dn5wC6npkFLXnsAOKLjx49AmUHLYAAAwBoQubG016R5wAAAABJRU5ErkJggg==) no-repeat top left; | ||||
|             } | ||||
|             .sf-button .border-r { | ||||
|                 padding: 0 7px 0 0; | ||||
|                 background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAcCAYAAACtQ6WLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAR1JREFUeNpiPHnyZCMDA8MNID5gZmb2nAEJMH7//v3N169fX969e/cYkL8WqGAHXPLv37//QYzfv39/fvPmzbUnT56sAXInmJub/2H5/x8sx8DCwsIrISFhDmQyPX78+CmQXs70798/BmQsKipqBNTgdvz4cWkmkE5kDATMioqKZkCFdiwg1eiAi4tLGqhQF24nMmBmZuYEigth1QkEbEBxTlySYPvJkwSJ00AnjYylgU6gxB8g/oFVEphkvgLF32KNMmCCewYUv4qhEyj47+HDhyeBzIMYOoEp8CxQw56wsLAncJ1//vz5/P79+2svX74EJc2V4BT58+fPd8CE/QKYHMGJOiIiAp6oWW7evDkNSF8DZYfIyEiU7AAQYACJ2vxVdJW4eQAAAABJRU5ErkJggg==) right top no-repeat; | ||||
|             } | ||||
|             .sf-button .btn-bg { | ||||
|                 padding: 0 14px; | ||||
|                 color: #636363; | ||||
|                 line-height: 28px; | ||||
|                 background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAcCAYAAACgXdXMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAClJREFUeNpiPnny5EKGf//+/Wf6//8/A4QAcrGzKCZwGc9sa2urBBBgAIbDUoYVp9lmAAAAAElFTkSuQmCC) repeat-x top left; | ||||
|             } | ||||
|             .sf-button:hover .border-l, | ||||
|             .sf-button-selected .border-l { | ||||
|                 background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAcCAYAAACtQ6WLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAR9JREFUeNpi/P//PwMyOHfunDqQSgNiexZkibNnzxYBqZa3HOs5v7PcYQBLnjlzhg1IbfzIdsTjA/t+ht9Mr8GKwZL//v3r+sB+0OMN+zqIEf8gFMvJkyd1gXTOa9YNDP//otrPAtSV/Jp9HfPff78Z0AEL0LUeXxivMfxD0wXTqfjj/2ugkf+wSrL9/YtpJEyS4S8WI5Ek/+GR/POPFjr//cenE6/kP9q4Fo/kr39/mdj+M/zFkGQCSj5i+ccPjLJ/GBgkuYOHQR1sNDpmAkb2LBmWwL///zKCIxwZM0VHR18G6p4uxeLLAA4tJMwEshiou1iMxXaHLGswA+t/YbhORuQUv2DBAnCifvxzI+enP3dQJUFg/vz5sOzgBBBgAPxX9j0YnH4JAAAAAElFTkSuQmCC) no-repeat top left; | ||||
|             } | ||||
|             .sf-button:hover .border-r, | ||||
|             .sf-button-selected .border-r { | ||||
|                 background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAcCAYAAACtQ6WLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAT5JREFUeNpiPHv27BkGBoaDQDzLyMjoJgMSYHrM3WX8hn1d0f///88DFRYhSzIuv2X5H8Rg/SfKIPDTkYH/l80OINffxMTkF9O/f/8ZQPgnwyuGl+wrGd6x7vf49+9fO9jYf3+Bkkj4NesmBqAV+SdPntQC6vzHgIz//gOawbqOGchOxtAJwp8Zr4F0e7D8/fuPAR38/P8eZIo0yz8skv8YvoIk+YE6/zNgAyD7sRqLkPzzjxY6/+HS+R+fTkZ8djLh08lCUCcuSWawJGbwMTGwg7zyBatX2Bj5QZKPsBrLzaICktzN8g/NWEYGZgYZjoC/wMiei5FMpFh8QPSU6Ojoy3Cd7EwiDBJsDgxiLNY7gLrKQGIsHAxSDHxAO2TZ/b8D+TVxcXF9MCtYtLiKLgDpfUDVsxITE1GyA0CAAQA2E/N8VuHyAAAAAABJRU5ErkJggg==) right top no-repeat; | ||||
|             } | ||||
|             .sf-button:hover .btn-bg, | ||||
|             .sf-button-selected .btn-bg { | ||||
|                 color: #FFFFFF; | ||||
|                 text-shadow:0 1px 1px #6b9311; | ||||
|                 background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAcCAIAAAAvP0KbAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAEFJREFUeNpiPnv2LNMdvlymf///M/37B8R/QfQ/MP33L4j+B6Qh7L9//sHpf2h8MA1V+w/KRjYLaDaLCU8vQIABAFO3TxZriO4yAAAAAElFTkSuQmCC) repeat-x top left; | ||||
|             } | ||||
|  | ||||
|             /* styles copied from bundles/sensiodistribution/webconfigurator/css/install.css */ | ||||
|             body { | ||||
|                 font-size: 14px; | ||||
|                 font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; | ||||
|             } | ||||
|             .sf-reset h1.title { | ||||
|                 font-size: 45px; | ||||
|                 padding-bottom: 30px; | ||||
|             } | ||||
|             .sf-reset h2 { | ||||
|                 font-weight: bold; | ||||
|                 color: #FFFFFF; | ||||
|                 /* Font is reset to sans-serif (like body) */ | ||||
|                 font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; | ||||
|                 margin-bottom: 10px; | ||||
|                 background-color: #aacd4e; | ||||
|                 padding: 2px 4px; | ||||
|                 display: inline-block; | ||||
|                 text-transform: uppercase; | ||||
|             } | ||||
|             .sf-reset ul a, | ||||
|             .sf-reset ul a:hover { | ||||
|                 background: url(../images/blue-arrow.png) no-repeat right 6px; | ||||
|                 padding-right: 10px; | ||||
|             } | ||||
|             .sf-reset ul, ol { | ||||
|                 padding-left: 20px; | ||||
|             } | ||||
|             .sf-reset li { | ||||
|                 padding-bottom: 18px; | ||||
|             } | ||||
|             .sf-reset ol li { | ||||
|                 list-style-type: decimal; | ||||
|             } | ||||
|             .sf-reset ul li { | ||||
|                 list-style-type: none; | ||||
|             } | ||||
|             .sf-reset .symfony-blocks-install { | ||||
|                 overflow: hidden; | ||||
|             } | ||||
|             .sf-reset .symfony-install-continue { | ||||
|                 font-size: 0.95em; | ||||
|                 padding-left: 0; | ||||
|             } | ||||
|             .sf-reset .symfony-install-continue li { | ||||
|                 padding-bottom: 10px; | ||||
|             } | ||||
|             .sf-reset .ok { | ||||
|                 color: #fff; | ||||
|                 font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; | ||||
|                 background-color: #6d6; | ||||
|                 padding: 10px; | ||||
|                 margin-bottom: 20px; | ||||
|             } | ||||
|             .sf-reset .ko { | ||||
|                 background-color: #d66; | ||||
|             } | ||||
|             .sf-reset p.help { | ||||
|                 padding: 12px 16px; | ||||
|                 word-break: break-word; | ||||
|             } | ||||
|             .version { | ||||
|                 text-align: right; | ||||
|                 font-size: 10px; | ||||
|                 margin-right: 20px; | ||||
|             } | ||||
|             .sf-reset a, | ||||
|             .sf-reset li a { | ||||
|                 color: #08C; | ||||
|                 text-decoration: none; | ||||
|             } | ||||
|             .sf-reset a:hover, | ||||
|             .sf-reset li a:hover { | ||||
|                 color: #08C; | ||||
|                 text-decoration: underline; | ||||
|             } | ||||
|             .sf-reset textarea { | ||||
|                 padding: 7px; | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
|     <body> | ||||
|         <div id="content"> | ||||
|             <div class="header clear-fix"> | ||||
|                 <div class="header-logo"> | ||||
|                     <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALYAAAA+CAMAAACxzRGDAAAAUVBMVEX////Ly8yko6WLioxkYmVXVVkwLjLl5eWxsLJKSEzy8vJxcHLY2Ni+vb89Oz9XVVh+fH+Yl5n///+xsbLY2Nlxb3KkpKWXlph+fX+LiYy+vr/IZP61AAAAAXRSTlMAQObYZgAABRBJREFUeNrVmtuWoyAQRS1FEEQSzQU7//+hYxUiXsKQZLJWM+chsUloN+WhCuguYoKyYqzmvGasKqH4HyRKxndipcgcumH8qViTM7TkUclcwaHmf5XM0eWq4km1KjdqXfMXJHVe1J3hL8lk5fCGv6wmT+o0d87U+XNrk0Y9nfv+7LM6ZJH5ZBL6LAbSxQ3Q5FDr22Skr8PQSy4n7isnsQxSX4r6pobhjCHHeDNOKrO3yGmCvZOjV9jmt8ulTdXFKdbKLNh+kOMvBzuVRa4Y7MUsdEUSWQe7xxCfZmcwjHU83LqzFvSbJQOXQvptbPnEFoyZtUUGwTeKuLuTHyT1kaP0P6cR01OKvv448gtl61dqZfmJezQmU/t+1R2fJLtBwXV6uWGwB9SZPrn0fKO2WAvQN1PUhHjTom3xgXYTkvlSKHs19OhslETq6X3HrXbjt8XbGj9b4Gi+lUAnL6XxQj8Pyk9N4Bt1xUrsLVN/3isYMug8rODMdbgOvoHs8uAb2fcANIAzkKCLYy+AXRpSU8sr1r4P67xhLgPp7vM32zlqt7Bhq2fI1Hwp+VgANxok59SsGV3oqdUL0YVDMRY7Yg8QLbVUU4NZNoOq5hJHuxEM28Sh/IyUZ8D3reR+yc58EGvOy2U0HQL6G9V+kWyEWHmzaMx6t4o9RhOm/riUiYrzqij4Ptqkn7AaCXqc+F47m04ahfde7YIz8RHEBN6BdVwdIGRVdNbKqYu1Hc0x0wBY4wqC8+XUgBGnj81SZsQB+0yAS1x/BlI/6ebHHk0lauQLuPDpu6EwAVJ7T0rl2uXa23jcqNyOZekhqYHRz3JOANrF4wCCmEs1f9D1lUe0n4NAATed80Y5e0Q7CO2TezM/BR6wKdgQzKbCF4uOQC3Bk0fKAzbFlyRWg3gksA/gmm7eOjrpaKX7fHlEW2xLbE6GZsPiCiShVzN7RG2xTz2G+OJtEqzdJ7APxy3MrSsV0VukXbKMp9lhs5BN6dr3CN+sySUaoxGwfRUM3I/gdPYONgVU+PLX4vUWm32AvUySarbONvcpV2RQEPKKjEBHFk01kQDGRblnn8ZuE9g+JUl8OWAPbkFK2K6JxhJVvF47FzYYnAN22ttwxKYCoH36rheEB7KG/HF/YUaa2G5JF+55tpyrl7B1WHM39HuP2N2EXPl1UBu8vbj4OjvD+NoTE4ssF+ScARgaJY1N7+u8bY/Y9BSM5PKwJbvMVab32YP5FB5TtcYVrGoASolVLTzI7kVsYVxRtAb5n2JXq1vCdtd47XtYItynrN0835PasLg0y13aOPbmPI+on2Lr9e5tjSHvgkAvclUjL3Fsdaw03IzgTR62yYClk7QMah4IQ0qSsoYYbOix6zJR1ZGDNMOY3Bb6W5S6jiyovep3t7bUPyoq7OkjYumrfESp8zSBc/OLosVf+nTnnKjsqR16++WDwpI8FxJWRFTlI6NKnqYJaL96TqjAbo9Toi5QiWBDcmfdFV+T8dkvFe5bItgstbM2X6QG2mVun+cazfRwOS0eiaeRRJKgLfc3BQAqfnhJyz8lfR6580SF/FXVu83Nz1xrrnFqqXL6Qxl47DNSm4RFflvN5sABDD8peouqLLKQXVdGbnqf+qIpOxON4ZyYdJEJ6sy4zS2c5eRPTT4Jyp46qDE5/ptAWqJOQ9e6yE82FXBbZCk1/tXVoshVoopE3CB0zmraI3nbqCJ/gW3ZMgtbC5nh/QHlOoOZBxQCRgAAAABJRU5ErkJggg==" alt="Symfony" /> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="search"> | ||||
|                   <form method="get" action="http://symfony.com/search"> | ||||
|                     <div class="form-row"> | ||||
|  | ||||
|                       <label for="search-id"> | ||||
|                                 <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAABUElEQVQoz2NgAIJ29iBdD0d7X2cPb+tY2f9MDMjgP2O2hKu7vS8CBlisZUNSMJ3fxRMkXO61wm2ue6I3iB1q8Z8ZriDZFCS03fm/wX+1/xp/TBo8QPxeqf+MUAW+QIFKj/+q/wX/c/3n/i/6Qd/bx943z/Q/K1SBI1D9fKv/AhCn/Wf5L5EHdFGKw39OqAIXoPpOMziX4T9/DFBBnuN/HqhAEtCKCNf/XDA/rZRyAmrpsvrPDVUw3wrkqCiLaewg6TohX1d7X0ffs5r/OaAKfinmgt3t4ulr4+Xg4ANip3j+l/zPArNT4LNOD0pAgWCSOUIBy3+h/+pXbBa5tni0eMx23+/mB1YSYnENroT5Pw/QSOX/mkCo+l/jgo0v2KJA643s8PgAmsMBDCbu/5xALHPB2husxN9uCzsDOgAq5kAoaZVnYMCh5Ky1r88Eh/+iABM8jUk7ClYIAAAAAElFTkSuQmCC" alt="Search on Symfony website" /> | ||||
|                       </label> | ||||
|  | ||||
|                       <input name="q" id="search-id" type="search" placeholder="Search on Symfony website" /> | ||||
|  | ||||
|                       <button type="submit" class="sf-button"> | ||||
|                           <span class="border-l"> | ||||
|                             <span class="border-r"> | ||||
|                                 <span class="btn-bg">OK</span> | ||||
|                             </span> | ||||
|                         </span> | ||||
|                       </button> | ||||
|                     </div> | ||||
|                    </form> | ||||
|                 </div> | ||||
|             </div> | ||||
|  | ||||
|             <div class="sf-reset"> | ||||
|                 <div class="block"> | ||||
|                     <div class="symfony-block-content"> | ||||
|                         <h1 class="title">Configuration Checker</h1> | ||||
|                         <p> | ||||
|                             This script analyzes your system to check whether is | ||||
|                             ready to run Symfony applications. | ||||
|                         </p> | ||||
|  | ||||
|                         <?php if ($hasMajorProblems): ?> | ||||
|                             <h2 class="ko">Major problems</h2> | ||||
|                             <p>Major problems have been detected and <strong>must</strong> be fixed before continuing:</p> | ||||
|                             <ol> | ||||
|                                 <?php foreach ($majorProblems as $problem): ?> | ||||
|                                     <li><?php echo $problem->getTestMessage() ?> | ||||
|                                         <p class="help"><em><?php echo $problem->getHelpHtml() ?></em></p> | ||||
|                                     </li> | ||||
|                                 <?php endforeach; ?> | ||||
|                             </ol> | ||||
|                         <?php endif; ?> | ||||
|  | ||||
|                         <?php if ($hasMinorProblems): ?> | ||||
|                             <h2>Recommendations</h2> | ||||
|                             <p> | ||||
|                                 <?php if ($hasMajorProblems): ?>Additionally, to<?php else: ?>To<?php endif; ?> enhance your Symfony experience, | ||||
|                                 it’s recommended that you fix the following: | ||||
|                             </p> | ||||
|                             <ol> | ||||
|                                 <?php foreach ($minorProblems as $problem): ?> | ||||
|                                     <li><?php echo $problem->getTestMessage() ?> | ||||
|                                         <p class="help"><em><?php echo $problem->getHelpHtml() ?></em></p> | ||||
|                                     </li> | ||||
|                                 <?php endforeach; ?> | ||||
|                             </ol> | ||||
|                         <?php endif; ?> | ||||
|  | ||||
|                         <?php if ($symfonyRequirements->hasPhpIniConfigIssue()): ?> | ||||
|                             <p id="phpini">* | ||||
|                                 <?php if ($symfonyRequirements->getPhpIniConfigPath()): ?> | ||||
|                                     Changes to the <strong>php.ini</strong> file must be done in "<strong><?php echo $symfonyRequirements->getPhpIniConfigPath() ?></strong>". | ||||
|                                 <?php else: ?> | ||||
|                                     To change settings, create a "<strong>php.ini</strong>". | ||||
|                                 <?php endif; ?> | ||||
|                             </p> | ||||
|                         <?php endif; ?> | ||||
|  | ||||
|                         <?php if (!$hasMajorProblems && !$hasMinorProblems): ?> | ||||
|                             <p class="ok">All checks passed successfully. Your system is ready to run Symfony applications.</p> | ||||
|                         <?php endif; ?> | ||||
|  | ||||
|                         <ul class="symfony-install-continue"> | ||||
|                             <?php if ($hasMajorProblems || $hasMinorProblems): ?> | ||||
|                                 <li><a href="config.php">Re-check configuration</a></li> | ||||
|                             <?php endif; ?> | ||||
|                         </ul> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div class="version">Symfony Standard Edition</div> | ||||
|         </div> | ||||
|     </body> | ||||
| </html> | ||||
							
								
								
									
										
											BIN
										
									
								
								web/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.4 KiB | 
							
								
								
									
										5
									
								
								web/robots.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								web/robots.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| # www.robotstxt.org/ | ||||
| # www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449 | ||||
|  | ||||
| User-agent: * | ||||
| Disallow: | ||||
		Reference in New Issue
	
	Block a user