├── app ├── cache │ └── .gitkeep ├── logs │ └── .gitkeep ├── .htaccess ├── AppCache.php ├── config │ ├── security.yml │ ├── config_test.yml │ ├── routing_dev.yml │ ├── parameters.yml.dist │ ├── config_prod.yml │ ├── config_dev.yml │ ├── routing.yml │ └── config.yml ├── autoload.php ├── Resources │ ├── TwigBundle │ │ └── views │ │ │ └── Exception │ │ │ ├── error.html.twig │ │ │ └── error404.html.twig │ └── views │ │ ├── monthslist.html.twig │ │ └── base.html.twig ├── console ├── phpunit.xml.dist ├── AppKernel.php ├── check.php └── SymfonyRequirements.php ├── src ├── PowerGrid │ └── PowerGridBundle │ │ ├── Resources │ │ ├── doc │ │ │ └── index.rst │ │ ├── config │ │ │ ├── services.yml │ │ │ ├── routing.yml │ │ │ └── doctrine │ │ │ │ └── Status.orm.xml │ │ ├── translations │ │ │ └── messages.fr.xlf │ │ └── views │ │ │ └── Default │ │ │ ├── error.html.twig │ │ │ ├── contact.html.twig │ │ │ ├── infographic.html.twig │ │ │ ├── about.html.twig │ │ │ ├── api.html.twig │ │ │ ├── faq.html.twig │ │ │ ├── history.html.twig │ │ │ └── index.html.twig │ │ ├── PowerGridBundle.php │ │ ├── Entity │ │ ├── StatusRepository.php │ │ ├── Status.php │ │ └── Status.php~ │ │ ├── Tests │ │ └── Controller │ │ │ └── DefaultControllerTest.php │ │ ├── PowerGrid │ │ └── PowerGridService.php │ │ ├── DependencyInjection │ │ ├── Configuration.php │ │ └── PowerGridExtension.php │ │ ├── Command │ │ ├── SaveStatusNowCommand.php │ │ └── PrepDataForD3Command.php │ │ └── Controller │ │ └── DefaultController.php └── .htaccess ├── web ├── favicon.ico ├── favicon.png ├── apple-touch-icon.png ├── images │ ├── power-lines.jpg │ ├── 2014-infographic.png │ └── egyptian-power-grid-load-year-in-review-2014.png ├── robots.txt ├── app.php ├── app_dev.php ├── .htaccess └── config.php ├── .gitignore ├── UPGRADE-2.4.md ├── LICENSE ├── README.md ├── UPGRADE-2.2.md ├── UPGRADE-2.3.md ├── composer.json ├── UPGRADE.md └── gpl-2.0.txt /app/cache/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/logs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Resources/doc/index.rst: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mos3abof/gridstatusnow/HEAD/web/favicon.ico -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mos3abof/gridstatusnow/HEAD/web/favicon.png -------------------------------------------------------------------------------- /web/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mos3abof/gridstatusnow/HEAD/web/apple-touch-icon.png -------------------------------------------------------------------------------- /web/images/power-lines.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mos3abof/gridstatusnow/HEAD/web/images/power-lines.jpg -------------------------------------------------------------------------------- /web/images/2014-infographic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mos3abof/gridstatusnow/HEAD/web/images/2014-infographic.png -------------------------------------------------------------------------------- /web/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | # www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449 3 | 4 | User-agent: * 5 | -------------------------------------------------------------------------------- /web/images/egyptian-power-grid-load-year-in-review-2014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mos3abof/gridstatusnow/HEAD/web/images/egyptian-power-grid-load-year-in-review-2014.png -------------------------------------------------------------------------------- /app/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Order deny,allow 6 | Deny from all 7 | 8 | -------------------------------------------------------------------------------- /src/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Order deny,allow 6 | Deny from all 7 | 8 | -------------------------------------------------------------------------------- /app/AppCache.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Symfony2 is great 7 | J'aime Symfony2 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Tests/Controller/DefaultControllerTest.php: -------------------------------------------------------------------------------- 1 | request('GET', '/hello/Fabien'); 14 | 15 | $this->assertTrue($crawler->filter('html:contains("Hello Fabien")')->count() > 0); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/config/parameters.yml.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | database_driver: pdo_mysql 3 | database_host: 127.0.0.1 4 | database_port: ~ 5 | database_name: symfony 6 | database_user: root 7 | database_password: ~ 8 | 9 | mailer_transport: smtp 10 | mailer_host: 127.0.0.1 11 | mailer_user: ~ 12 | mailer_password: ~ 13 | 14 | locale: en 15 | secret: ThisTokenIsNotSoSecretChangeIt 16 | 17 | debug_toolbar: true 18 | debug_redirects: false 19 | use_assetic_controller: true 20 | -------------------------------------------------------------------------------- /app/config/config_prod.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: config.yml } 3 | 4 | #framework: 5 | # validation: 6 | # cache: apc 7 | 8 | #doctrine: 9 | # orm: 10 | # metadata_cache_driver: apc 11 | # result_cache_driver: apc 12 | # query_cache_driver: apc 13 | 14 | monolog: 15 | handlers: 16 | main: 17 | type: fingers_crossed 18 | action_level: error 19 | handler: nested 20 | nested: 21 | type: stream 22 | path: "%kernel.logs_dir%/%kernel.environment%.log" 23 | level: debug 24 | console: 25 | type: console 26 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Resources/config/doctrine/Status.orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/Resources/TwigBundle/views/Exception/error.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | 4 | {% block title %}Error : {{ status_text }} | Egypt Power Grid Load Status{% endblock %} 5 | 6 | 7 | {% block home_active %} active{% endblock %} 8 | 9 | 10 | {% block content %} 11 |
12 |

Ooops!

13 | 14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 |

22 | The dev is working onf fixing this shortly. 23 |

24 |
25 | 26 |
27 | 28 |
29 | 30 | 31 | {% endblock %} -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/PowerGrid/PowerGridService.php: -------------------------------------------------------------------------------- 1 | source_url)) == false) 14 | { 15 | throw new \Exception("Source seems to be down", 1); 16 | } 17 | 18 | if(stripos($content, 'images/c3.gif') !== false) 19 | { 20 | return 'Danger'; 21 | } 22 | elseif(stripos($content, 'images/c2.gif') !== false) 23 | { 24 | return 'Warning'; 25 | } 26 | elseif(stripos($content, 'images/c1.gif') !== false) 27 | { 28 | return 'Safe'; 29 | } 30 | } 31 | catch(\Exception $e) 32 | { 33 | return 'Unknown'; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Resources/views/Default/error.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | 4 | {% block title %}Error : Page Not Found | Egypt Power Grid Load Status{% endblock %} 5 | 6 | {% block content %} 7 |
8 |

{{ error_title }}

9 | 10 |
11 | 12 |
13 | 14 |
15 | 16 |
17 |

18 | You might want to go back to the home page! 19 |

20 |
21 | 22 |
23 | 24 |
25 | 26 | 27 | {% endblock %} -------------------------------------------------------------------------------- /app/Resources/TwigBundle/views/Exception/error404.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | 4 | {% block title %}Error : Page Not Found | Egypt Power Grid Load Status{% endblock %} 5 | 6 | 7 | {% block home_active %} active{% endblock %} 8 | 9 | 10 | {% block content %} 11 |
12 |

Page Not Found!

13 | 14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 |

22 | You might want to go back to the home page! 23 |

24 |
25 | 26 |
27 | 28 |
29 | 30 | 31 | {% endblock %} -------------------------------------------------------------------------------- /app/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev'); 19 | $debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod'; 20 | 21 | if ($debug) { 22 | Debug::enable(); 23 | } 24 | 25 | $kernel = new AppKernel($env, $debug); 26 | $application = new Application($kernel); 27 | $application->run($input); 28 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | root('power_grid'); 22 | 23 | // Here you should define the parameters that are allowed to 24 | // configure your bundle. See the documentation linked above for 25 | // more information on that topic. 26 | 27 | return $treeBuilder; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/DependencyInjection/PowerGridExtension.php: -------------------------------------------------------------------------------- 1 | processConfiguration($configuration, $configs); 24 | 25 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 26 | $loader->load('services.yml'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /web/app.php: -------------------------------------------------------------------------------- 1 | unregister(); 14 | $apcLoader->register(true); 15 | */ 16 | 17 | require_once __DIR__.'/../app/AppKernel.php'; 18 | //require_once __DIR__.'/../app/AppCache.php'; 19 | 20 | $kernel = new AppKernel('prod', false); 21 | $kernel->loadClassCache(); 22 | //$kernel = new AppCache($kernel); 23 | 24 | // When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter 25 | //Request::enableHttpMethodParameterOverride(); 26 | $request = Request::createFromGlobals(); 27 | $response = $kernel->handle($request); 28 | $response->send(); 29 | $kernel->terminate($request, $response); 30 | -------------------------------------------------------------------------------- /app/config/config_dev.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: config.yml } 3 | 4 | framework: 5 | router: 6 | resource: "%kernel.root_dir%/config/routing_dev.yml" 7 | strict_requirements: true 8 | profiler: { only_exceptions: false } 9 | 10 | web_profiler: 11 | toolbar: "%debug_toolbar%" 12 | intercept_redirects: "%debug_redirects%" 13 | 14 | monolog: 15 | handlers: 16 | main: 17 | type: stream 18 | path: "%kernel.logs_dir%/%kernel.environment%.log" 19 | level: debug 20 | console: 21 | type: console 22 | bubble: false 23 | # uncomment to get logging in your browser 24 | # you may have to allow bigger header sizes in your Web server configuration 25 | #firephp: 26 | # type: firephp 27 | # level: info 28 | #chromephp: 29 | # type: chromephp 30 | # level: info 31 | 32 | assetic: 33 | use_controller: "%use_assetic_controller%" 34 | 35 | #swiftmailer: 36 | # delivery_address: me@example.com 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004-2014 Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /app/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | ../src/*/*Bundle/Tests 13 | ../src/*/Bundle/*Bundle/Tests 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | ../src 26 | 27 | ../src/*/*Bundle/Resources 28 | ../src/*/*Bundle/Tests 29 | ../src/*/Bundle/*Bundle/Resources 30 | ../src/*/Bundle/*Bundle/Tests 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /web/app_dev.php: -------------------------------------------------------------------------------- 1 | loadClassCache(); 27 | $request = Request::createFromGlobals(); 28 | $response = $kernel->handle($request); 29 | $response->send(); 30 | $kernel->terminate($request, $response); 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Grid Status Now 2 | =============== 3 | 4 | This is an attempt at parsing the data in the [Load Meter][1] provided by 5 | The Egyptian Electric Utility and Consumer Protection Regulatory Agency ([EGYPTERA][2]). 6 | 7 | You can visit the site [here][3]. 8 | 9 | 10 | Contributors 11 | ============ 12 | 13 | Khaled Attia ([@khal3d][4]) 14 | 15 | License 16 | ======= 17 | 18 | 19 | Grid Status Now 20 | Copyright (C) 2014 Mosab Ahmad 21 | 22 | This program is free software; you can redistribute it and/or 23 | modify it under the terms of the GNU General Public License 24 | as published by the Free Software Foundation; either version 2 25 | of the License, or (at your option) any later version. 26 | 27 | This program is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU General Public License for more details. 31 | 32 | You should have received a copy of the GNU General Public License 33 | along with this program; if not, write to the Free Software 34 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 35 | 36 | 37 | [1]: http://loadmeter.egyptera.org/MiniCurrentLoadClock3.aspx 38 | [2]: http://egyptera.org/ar/ 39 | [3]: http://www.gridstatusnow.com/ 40 | [4]: https://github.com/khal3d 41 | -------------------------------------------------------------------------------- /UPGRADE-2.2.md: -------------------------------------------------------------------------------- 1 | UPGRADE FROM 2.1 to 2.2 2 | ======================= 3 | 4 | * The [`web/.htaccess`](https://github.com/symfony/symfony-standard/blob/2.2/web/.htaccess) 5 | file has been enhanced substantially to prevent duplicate content with and 6 | without `/app.php` in the URI. It also improves functionality when using 7 | Apache aliases or when mod_rewrite is not available. So you might want to 8 | update your `.htaccess` file as well. 9 | 10 | * The ``_internal`` route is not used any more. It should then be removed 11 | from both your routing and security configurations. A ``fragments`` key has 12 | been added to the framework configuration and must be specified when ESI or 13 | Hinclude are in use. No security configuration is required for this path as 14 | by default ESI access is only permitted for trusted hosts and Hinclude 15 | access uses an URL signing mechanism. 16 | 17 | ``` 18 | framework: 19 | # ... 20 | fragments: { path: /_proxy } 21 | ``` 22 | 23 | Functional Tests 24 | ---------------- 25 | 26 | * The profiler has been disabled by default in the test environment. You can 27 | enable it again by modifying the ``config_test.yml`` configuration file or 28 | even better, you can just enable it for the very next request by calling 29 | ``$client->enableProfiler()`` when you need the profiler in a test (that 30 | speeds up functional tests quite a bit). 31 | -------------------------------------------------------------------------------- /app/config/routing.yml: -------------------------------------------------------------------------------- 1 | home_page: 2 | pattern: / 3 | defaults: { _controller: PowerGridBundle:Default:index } 4 | 5 | status: 6 | pattern: /status 7 | defaults: { _controller: PowerGridBundle:Default:status } 8 | 9 | history: 10 | pattern: /history 11 | defaults: { _controller: PowerGridBundle:Default:history } 12 | 13 | 14 | history_archive_month_and_year: 15 | pattern: /history/{year}/{month} 16 | defaults: { _controller: PowerGridBundle:Default:history } 17 | 18 | history_day_tsv: 19 | pattern: /history/tsv/{year}/{month}/{day} 20 | defaults: { _controller: PowerGridBundle:Default:historytsv } 21 | 22 | history_archive_month_and_year_tsv: 23 | pattern: /history/tsv/{year}/{month} 24 | defaults: { _controller: PowerGridBundle:Default:historytsv } 25 | 26 | infographic: 27 | pattern: /infographic/2014 28 | defaults: { _controller: PowerGridBundle:Default:yearlyinfographic } 29 | api: 30 | pattern: /api 31 | defaults: { _controller: PowerGridBundle:Default:api} 32 | 33 | about: 34 | pattern: /about 35 | defaults: { _controller: PowerGridBundle:Default:about} 36 | 37 | contact: 38 | pattern: /contact 39 | defaults: { _controller: PowerGridBundle:Default:contact} 40 | 41 | faq: 42 | pattern: /faq 43 | defaults: { _controller: PowerGridBundle:Default:faq} 44 | 45 | # power_grid: 46 | # resource: "@PowerGridBundle/Resources/config/routing.yml" 47 | # prefix: / 48 | # 49 | -------------------------------------------------------------------------------- /app/AppKernel.php: -------------------------------------------------------------------------------- 1 | getEnvironment(), array('dev', 'test'))) { 23 | $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); 24 | $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); 25 | $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); 26 | } 27 | 28 | return $bundles; 29 | } 30 | 31 | public function registerContainerConfiguration(LoaderInterface $loader) 32 | { 33 | $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Entity/Status.php: -------------------------------------------------------------------------------- 1 | id; 40 | } 41 | 42 | /** 43 | * Set status 44 | * 45 | * @param string $status 46 | * @return Status 47 | */ 48 | public function setStatus($status) 49 | { 50 | $this->status = $status; 51 | 52 | return $this; 53 | } 54 | 55 | /** 56 | * Get status 57 | * 58 | * @return string 59 | */ 60 | public function getStatus() 61 | { 62 | return $this->status; 63 | } 64 | 65 | 66 | /** 67 | * @var \DateTime 68 | */ 69 | private $timestamp; 70 | 71 | 72 | /** 73 | * Set timestamp 74 | * 75 | * @param \DateTime $timestamp 76 | * @return Status 77 | */ 78 | public function setTimestamp($timestamp) 79 | { 80 | $this->timestamp = $timestamp; 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * Get timestamp 87 | * 88 | * @return \DateTime 89 | */ 90 | public function getTimestamp() 91 | { 92 | return $this->timestamp; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Entity/Status.php~: -------------------------------------------------------------------------------- 1 | id; 47 | } 48 | 49 | /** 50 | * Set status 51 | * 52 | * @param string $status 53 | * @return Status 54 | */ 55 | public function setStatus($status) 56 | { 57 | $this->status = $status; 58 | 59 | return $this; 60 | } 61 | 62 | /** 63 | * Get status 64 | * 65 | * @return string 66 | */ 67 | public function getStatus() 68 | { 69 | return $this->status; 70 | } 71 | 72 | /** 73 | * Set parsedAt 74 | * 75 | * @param \DateTime $parsedAt 76 | * @return Status 77 | */ 78 | public function setParsedAt($parsedAt) 79 | { 80 | $this->parsedAt = $parsedAt; 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * Get parsedAt 87 | * 88 | * @return \DateTime 89 | */ 90 | public function getParsedAt() 91 | { 92 | return $this->parsedAt; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /UPGRADE-2.3.md: -------------------------------------------------------------------------------- 1 | UPGRADE FROM 2.2 to 2.3 2 | ======================= 3 | 4 | When upgrading Symfony from 2.2 to 2.3, you need to do the following changes 5 | to the code that came from the Standard Edition: 6 | 7 | * The debugging tools are not enabled by default anymore and should be added 8 | to the 9 | [`web/app_dev.php`](https://github.com/symfony/symfony-standard/blob/2.3/web/app_dev.php) 10 | front controller manually, just after including the bootstrap cache: 11 | 12 | use Symfony\Component\Debug\Debug; 13 | 14 | Debug::enable(); 15 | 16 | You also need to enable debugging in the 17 | [`app/console`](https://github.com/symfony/symfony-standard/blob/2.3/app/console) 18 | script, after the `$debug` variable is defined: 19 | 20 | use Symfony\Component\Debug\Debug; 21 | 22 | if ($debug) { 23 | Debug::enable(); 24 | } 25 | 26 | * The `parameters.yml` file can now be managed by the 27 | `incenteev/composer-parameter-handler` bundle that comes with the 2.3 28 | Standard Edition: 29 | 30 | * add `"incenteev/composer-parameter-handler": "~2.0"` to your 31 | `composer.json` file; 32 | 33 | * add `/app/config/parameters.yml` to your `.gitignore` file; 34 | 35 | * create a 36 | [`app/config/parameters.yml.dist`](https://github.com/symfony/symfony-standard/blob/2.3/app/config/parameters.yml.dist) 37 | file with sensible values for all your parameters. 38 | 39 | * It is highly recommended that you switch the minimum stability to `stable` 40 | in your `composer.json` file. 41 | 42 | * If you are using Apache, have a look at the new 43 | [`.htaccess`](https://github.com/symfony/symfony-standard/blob/2.3/web/.htaccess) 44 | configuration and change yours accordingly. 45 | 46 | * In the 47 | [`app/autoload.php`](https://github.com/symfony/symfony-standard/blob/2.3/app/autoload.php) 48 | file, the section about `intl` should be removed as it is not needed anymore. 49 | 50 | You can also have a look at the 51 | [diff](https://github.com/symfony/symfony-standard/compare/v2.2.0%E2%80%A62.3) 52 | between the 2.2 version of the Standard Edition and the 2.3 version. 53 | -------------------------------------------------------------------------------- /app/config/config.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: parameters.yml } 3 | - { resource: security.yml } 4 | 5 | framework: 6 | #esi: ~ 7 | #translator: { fallback: "%locale%" } 8 | secret: "%secret%" 9 | router: 10 | resource: "%kernel.root_dir%/config/routing.yml" 11 | strict_requirements: ~ 12 | form: ~ 13 | csrf_protection: ~ 14 | validation: { enable_annotations: true } 15 | templating: 16 | engines: ['twig'] 17 | #assets_version: SomeVersionScheme 18 | default_locale: "%locale%" 19 | trusted_hosts: ~ 20 | trusted_proxies: ~ 21 | session: 22 | # handler_id set to null will use default session handler from php.ini 23 | handler_id: ~ 24 | fragments: ~ 25 | http_method_override: true 26 | 27 | # Twig Configuration 28 | twig: 29 | debug: "%kernel.debug%" 30 | strict_variables: "%kernel.debug%" 31 | 32 | # Assetic Configuration 33 | assetic: 34 | debug: "%kernel.debug%" 35 | use_controller: false 36 | bundles: [ ] 37 | #java: /usr/bin/java 38 | filters: 39 | cssrewrite: ~ 40 | #closure: 41 | # jar: "%kernel.root_dir%/Resources/java/compiler.jar" 42 | #yui_css: 43 | # jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar" 44 | 45 | # Doctrine Configuration 46 | doctrine: 47 | dbal: 48 | driver: "%database_driver%" 49 | host: "%database_host%" 50 | port: "%database_port%" 51 | dbname: "%database_name%" 52 | user: "%database_user%" 53 | password: "%database_password%" 54 | charset: UTF8 55 | # if using pdo_sqlite as your database driver, add the path in parameters.yml 56 | # e.g. database_path: "%kernel.root_dir%/data/data.db3" 57 | # path: "%database_path%" 58 | 59 | orm: 60 | auto_generate_proxy_classes: "%kernel.debug%" 61 | auto_mapping: true 62 | 63 | # Swiftmailer Configuration 64 | swiftmailer: 65 | transport: "%mailer_transport%" 66 | host: "%mailer_host%" 67 | username: "%mailer_user%" 68 | password: "%mailer_password%" 69 | spool: { type: memory } 70 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Resources/views/Default/contact.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | 4 | {% block title %}Contact | Grid Status Now{% endblock %} 5 | 6 | {% block fb %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% endblock %} 21 | 22 | {% block contact_active %} active{% endblock %} 23 | 24 | 25 | {% block content %} 26 |
27 |

Grid Status Now »

28 | 29 |

Contact Us

30 | 31 |
32 | 33 |
34 | 35 |
36 | 37 |
38 |

39 | If you have any feedback, question or suggestions, you can drop us a line on info@gridstatusnow.com. 40 |

41 |

42 | You can also follow us on Twitter (@gridstatusnow) 43 | or like our facebook page. 44 | 45 |

46 | 47 |
48 | 49 |
50 | 51 | {% endblock %} 52 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Command/SaveStatusNowCommand.php: -------------------------------------------------------------------------------- 1 | setName('power:savestatusnow') 18 | ->setDescription('Saves current power status to database'); 19 | } 20 | 21 | 22 | protected function execute(InputInterface $input, OutputInterface $output) 23 | { 24 | try 25 | { 26 | $tz = $this->getContainer()->getParameter('default_timezone');; 27 | $plus = $this->getContainer()->getParameter('gmt_as_number'); 28 | $date = new \DateTime("now"); 29 | $date->setTimezone(new \DateTimeZone($tz))->modify('+' . $plus .' hour'); 30 | $output->writeln(sprintf('[%s] Parsing time is (%s) Egypt local time ...', date('G:i:s'), $date->format('l, F jS h:i:s'))); 31 | 32 | $powerGridService = $this->getContainer()->get('power_grid_service'); 33 | $status = $powerGridService->getStatus(); 34 | 35 | if( $status ) 36 | { 37 | $em = $this->getContainer()->get('doctrine')->getManager(); 38 | 39 | $record = new Status(); 40 | $record->setStatus($status); 41 | $record->setTimestamp($date); 42 | 43 | $em->persist($record); 44 | $em->flush(); 45 | 46 | $output->writeln(sprintf('[%s] NEW STATUS (%s) ...', date('G:i:s'), $status)); 47 | } 48 | else { 49 | $output->writeln(sprintf('[%s] UNKNOWN STATUS, TRY AGAIN ...', date('G:i:s'))); 50 | } 51 | 52 | } catch (\Exception $e) { 53 | $this->getContainer()->get('doctrine')->resetManager(); 54 | $output->writeln(sprintf('[%s] [error] %s', date('G:i:s'), $e->getMessage())); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Resources/views/Default/infographic.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | 4 | {% block title %} Yearly Infographic For The Year 2014 | Grid Status Now{% endblock %} 5 | 6 | {% block fb %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% endblock %} 21 | 22 | {% block history_active %} active{% endblock %} 23 | 24 | 25 | {% block content %} 26 |
27 |

Grid Status Now »

28 | 29 |

Year In Review: How The Load On The Egyptian Power Grid Looked Like Through 2014

30 |
31 |

32 | 33 | Click here to download the infographic (.png file) 34 | 35 | 36 |

37 |
38 | 39 |
40 | 41 |
42 | 43 |
44 |

45 | 46 |

47 | 48 | 49 | Click here to download the infographic (.png file) 50 | 51 | 52 | 53 |
54 | 55 |
56 | 57 |
58 | 59 | {% endblock %} 60 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony/framework-standard-edition", 3 | "license": "MIT", 4 | "type": "project", 5 | "description": "The \"Symfony Standard Edition\" distribution", 6 | "autoload": { 7 | "psr-0": { "": "src/", "SymfonyStandard": "app/" } 8 | }, 9 | "require": { 10 | "php": ">=5.3.3", 11 | "symfony/symfony": "2.5.*", 12 | "doctrine/orm": "~2.2,>=2.2.3", 13 | "doctrine/doctrine-bundle": "~1.2", 14 | "twig/extensions": "~1.0", 15 | "symfony/assetic-bundle": "~2.3", 16 | "symfony/swiftmailer-bundle": "~2.3", 17 | "symfony/monolog-bundle": "~2.4", 18 | "sensio/distribution-bundle": "~3.0", 19 | "sensio/framework-extra-bundle": "~3.0", 20 | "incenteev/composer-parameter-handler": "~2.0", 21 | "symfony/filesystem": "2.6.*@dev" 22 | }, 23 | "require-dev": { 24 | "sensio/generator-bundle": "~2.3" 25 | }, 26 | "scripts": { 27 | "post-root-package-install": [ 28 | "SymfonyStandard\\Composer::hookRootPackageInstall" 29 | ], 30 | "post-install-cmd": [ 31 | "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", 32 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", 33 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", 34 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", 35 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", 36 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::removeSymfonyStandardFiles" 37 | ], 38 | "post-update-cmd": [ 39 | "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", 40 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", 41 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", 42 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", 43 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", 44 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::removeSymfonyStandardFiles" 45 | ] 46 | }, 47 | "config": { 48 | "bin-dir": "bin" 49 | }, 50 | "extra": { 51 | "symfony-app-dir": "app", 52 | "symfony-web-dir": "web", 53 | "incenteev-parameters": { 54 | "file": "app/config/parameters.yml" 55 | }, 56 | "branch-alias": { 57 | "dev-master": "2.5-dev" 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /web/.htaccess: -------------------------------------------------------------------------------- 1 | # Use the front controller as index file. It serves as a fallback solution when 2 | # every other rewrite/redirect fails (e.g. in an aliased environment without 3 | # mod_rewrite). Additionally, this reduces the matching process for the 4 | # start page (path "/") because otherwise Apache will apply the rewriting rules 5 | # to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl). 6 | DirectoryIndex app.php 7 | 8 | 9 | RewriteEngine On 10 | 11 | # Determine the RewriteBase automatically and set it as environment variable. 12 | # If you are using Apache aliases to do mass virtual hosting or installed the 13 | # project in a subdirectory, the base path will be prepended to allow proper 14 | # resolution of the app.php file and to redirect to the correct URI. It will 15 | # work in environments without path prefix as well, providing a safe, one-size 16 | # fits all solution. But as you do not need it in this case, you can comment 17 | # the following 2 lines to eliminate the overhead. 18 | RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ 19 | RewriteRule ^(.*) - [E=BASE:%1] 20 | 21 | # Redirect to URI without front controller to prevent duplicate content 22 | # (with and without `/app.php`). Only do this redirect on the initial 23 | # rewrite by Apache and not on subsequent cycles. Otherwise we would get an 24 | # endless redirect loop (request -> rewrite to front controller -> 25 | # redirect -> request -> ...). 26 | # So in case you get a "too many redirects" error or you always get redirected 27 | # to the start page because your Apache does not expose the REDIRECT_STATUS 28 | # environment variable, you have 2 choices: 29 | # - disable this feature by commenting the following 2 lines or 30 | # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the 31 | # following RewriteCond (best solution) 32 | RewriteCond %{ENV:REDIRECT_STATUS} ^$ 33 | RewriteRule ^app\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L] 34 | 35 | # If the requested filename exists, simply serve it. 36 | # We only want to let Apache serve files and not directories. 37 | RewriteCond %{REQUEST_FILENAME} -f 38 | RewriteRule .? - [L] 39 | 40 | # Rewrite all other queries to the front controller. 41 | RewriteRule .? %{ENV:BASE}/app.php [L] 42 | 43 | 44 | 45 | 46 | # When mod_rewrite is not available, we instruct a temporary redirect of 47 | # the start page to the front controller explicitly so that the website 48 | # and the generated links can still be used. 49 | RedirectMatch 302 ^/$ /app.php/ 50 | # RedirectTemp cannot be used instead 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/Resources/views/monthslist.html.twig: -------------------------------------------------------------------------------- 1 |

Archived Load History Graphs Are Available For

2 | 3 |
    4 |
  1. 5 | 6 | Nov 2015 7 | 8 |
  2. 9 |
  3. 10 | 11 | Oct 2015 12 | 13 |
  4. 14 |
  5. 15 | 16 | Sep 2015 17 | 18 |
  6. 19 |
  7. 20 | 21 | Aug 2015 22 | 23 |
  8. 24 |
  9. 25 | 26 | Jul 2015 27 | 28 |
  10. 29 |
  11. 30 | 31 | Jun 2015 32 | 33 |
  12. 34 | 35 |
  13. 36 | 37 | May 2015 38 | 39 |
  14. 40 | 41 |
  15. 42 | 43 | Apr 2015 44 | 45 |
  16. 46 | 47 |
  17. 48 | 49 | Mar 2015 50 | 51 |
  18. 52 | 53 |
  19. 54 | 55 | Feb 2015 56 | 57 |
  20. 58 | 59 |
  21. 60 | 61 | Jan 2015 62 | 63 |
  22. 64 | 65 |
  23. 66 | 67 | Dec 2014 68 | 69 |
  24. 70 | 71 |
  25. 72 | 73 | Nov 2014 74 | 75 |
  26. 76 | 77 |
  27. 78 | 79 | Oct 2014 80 | 81 |
  28. 82 | 83 |
  29. 84 | 85 | Sep 2014 86 | 87 |
  30. 88 | 89 |
  31. 90 | 91 | Aug 2014 92 | 93 |
  32. 94 |
95 | 96 |
97 | 98 |

Yearly Infographic

99 | 100 |
    101 |
  1. 102 | 2014 Infographic 103 | (.png file) 104 |
  2. 105 |
106 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Resources/views/Default/about.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | 4 | {% block title %}About Us | Grid Status Now{% endblock %} 5 | 6 | {% block fb %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% endblock %} 21 | 22 | {% block about_active %} active{% endblock %} 23 | 24 | 25 | {% block content %} 26 |
27 |

Grid Status Now »

28 | 29 |

About Us

30 | 31 |
32 | 33 |
34 | 35 |
36 | 37 |
38 |

39 | 40 | This service parses the data in the 41 | Load Meter 42 | provided by The Egyptian Electric Utility and Consumer Protection Regulatory Agency 43 | (EGYPTERA) 44 | and presents it in a more human friendly way. 45 |

46 | 47 |

48 | It also provides an API so other developers can build other web and mobile applications on top of it. 49 |

50 | 51 |

52 | This project was inspired by 53 | this post 54 | by 55 | Tarek Amr 56 | on Open Knowledge Foundation Egypt. 57 |

58 | 59 |

60 | If you build anything using this tool, please share it with me. I would love to see your creations :) 61 | Please contact me at : info@gridstatusnow.com. All feedback is welcome. 62 |

63 | 64 |
65 |

Project Featured On

66 |

67 |

79 |

80 | 81 |
82 | 83 |
84 | 85 |
86 | 87 | {% endblock %} 88 | -------------------------------------------------------------------------------- /app/check.php: -------------------------------------------------------------------------------- 1 | getPhpIniConfigPath(); 8 | 9 | echo_title('Symfony2 Requirements Checker'); 10 | 11 | echo '> PHP is using the following php.ini file:'.PHP_EOL; 12 | if ($iniPath) { 13 | echo_style('green', ' '.$iniPath); 14 | } else { 15 | echo_style('warning', ' WARNING: No configuration file (php.ini) used by PHP!'); 16 | } 17 | 18 | echo PHP_EOL.PHP_EOL; 19 | 20 | echo '> Checking Symfony requirements:'.PHP_EOL.' '; 21 | 22 | $messages = array(); 23 | foreach ($symfonyRequirements->getRequirements() as $req) { 24 | /** @var $req Requirement */ 25 | if ($helpText = get_error_message($req, $lineSize)) { 26 | echo_style('red', 'E'); 27 | $messages['error'][] = $helpText; 28 | } else { 29 | echo_style('green', '.'); 30 | } 31 | } 32 | 33 | $checkPassed = empty($messages['error']); 34 | 35 | foreach ($symfonyRequirements->getRecommendations() as $req) { 36 | if ($helpText = get_error_message($req, $lineSize)) { 37 | echo_style('yellow', 'W'); 38 | $messages['warning'][] = $helpText; 39 | } else { 40 | echo_style('green', '.'); 41 | } 42 | } 43 | 44 | if ($checkPassed) { 45 | echo_block('success', 'OK', 'Your system is ready to run Symfony2 projects', true); 46 | } else { 47 | echo_block('error', 'ERROR', 'Your system is not ready to run Symfony2 projects', true); 48 | 49 | echo_title('Fix the following mandatory requirements', 'red'); 50 | 51 | foreach ($messages['error'] as $helpText) { 52 | echo ' * '.$helpText.PHP_EOL; 53 | } 54 | } 55 | 56 | if (!empty($messages['warning'])) { 57 | echo_title('Optional recommendations to improve your setup', 'yellow'); 58 | 59 | foreach ($messages['warning'] as $helpText) { 60 | echo ' * '.$helpText.PHP_EOL; 61 | } 62 | } 63 | 64 | echo PHP_EOL; 65 | echo_style('title', 'Note'); 66 | echo ' The command console could use a different php.ini file'.PHP_EOL; 67 | echo_style('title', '~~~~'); 68 | echo ' than the one used with your web server. To be on the'.PHP_EOL; 69 | echo ' safe side, please check the requirements from your web'.PHP_EOL; 70 | echo ' server using the '; 71 | echo_style('yellow', 'web/config.php'); 72 | echo ' script.'.PHP_EOL; 73 | echo PHP_EOL; 74 | 75 | exit($checkPassed ? 0 : 1); 76 | 77 | function get_error_message(Requirement $requirement, $lineSize) 78 | { 79 | if ($requirement->isFulfilled()) { 80 | return; 81 | } 82 | 83 | $errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL.' ').PHP_EOL; 84 | $errorMessage .= ' > '.wordwrap($requirement->getHelpText(), $lineSize - 5, PHP_EOL.' > ').PHP_EOL; 85 | 86 | return $errorMessage; 87 | } 88 | 89 | function echo_title($title, $style = null) 90 | { 91 | $style = $style ?: 'title'; 92 | 93 | echo PHP_EOL; 94 | echo_style($style, $title.PHP_EOL); 95 | echo_style($style, str_repeat('~', strlen($title)).PHP_EOL); 96 | echo PHP_EOL; 97 | } 98 | 99 | function echo_style($style, $message) 100 | { 101 | // ANSI color codes 102 | $styles = array( 103 | 'reset' => "\033[0m", 104 | 'red' => "\033[31m", 105 | 'green' => "\033[32m", 106 | 'yellow' => "\033[33m", 107 | 'error' => "\033[37;41m", 108 | 'success' => "\033[37;42m", 109 | 'title' => "\033[34m", 110 | ); 111 | $supports = has_color_support(); 112 | 113 | echo ($supports ? $styles[$style] : '').$message.($supports ? $styles['reset'] : ''); 114 | } 115 | 116 | function echo_block($style, $title, $message) 117 | { 118 | $message = ' '.trim($message).' '; 119 | $width = strlen($message); 120 | 121 | echo PHP_EOL.PHP_EOL; 122 | 123 | echo_style($style, str_repeat(' ', $width).PHP_EOL); 124 | echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT).PHP_EOL); 125 | echo_style($style, str_pad($message, $width, ' ', STR_PAD_RIGHT).PHP_EOL); 126 | echo_style($style, str_repeat(' ', $width).PHP_EOL); 127 | } 128 | 129 | function has_color_support() 130 | { 131 | static $support; 132 | 133 | if (null === $support) { 134 | if (DIRECTORY_SEPARATOR == '\\') { 135 | $support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI'); 136 | } else { 137 | $support = function_exists('posix_isatty') && @posix_isatty(STDOUT); 138 | } 139 | } 140 | 141 | return $support; 142 | } 143 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Resources/views/Default/api.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | 4 | {% block title %}API Documentation | Grid Status Now{% endblock %} 5 | 6 | {% block fb %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {% endblock %} 22 | 23 | {% block api_active %} active{% endblock %} 24 | 25 | 26 | {% block content %} 27 |
28 |

Grid Status Now »

29 | 30 |

API Documentation

31 | 32 |
33 | 34 |
35 | 36 |
37 | 38 |
39 |

Overview

40 |

41 | For now, this API only exposes the current load status. But we plan on adding other functionalities soon. 42 |

43 |
44 | 45 |

REST API

46 |

GET /status

47 | 48 |

Description

49 | Get the current load status in JSON format. 50 |
51 | Unfortunately, the EGYPTERA load meter only depicts three values for the power grid load status, 52 | so the value of the JSON object will be either 53 | Danger, Warning or Safe. 54 | If the API fails to open and/or parse the source it will return the response Unknown. 55 |
56 |
57 |

Example Request

58 |
http://www.gridstatusnow.com/status
59 |
60 | 61 |

Example Response

62 |
{"status":"Danger"}
63 |
64 |
65 |

Examples

66 |

Python Example

67 |

68 |

#!/usr/bin/python
 69 | # -*- coding: utf-8 -*-
 70 | #@author Mosab Ahmad
 71 | 
 72 | import requests
 73 | import json
 74 | 
 75 | status = json.loads(requests.get('http://www.gridstatusnow.com/status').text)
 76 | 
 77 | print 'Power grid is now in the {} Zone!'.format(status['status'])
 78 |                  
79 | 80 | Output : 81 |
Power grid is now in the Danger Zone!
82 |

83 | 84 |
85 |

List Of Applications Using This API

86 |

87 |

    88 |
  • 89 | "Yalahweey", a desktop notification tool in Go programming language using the API written by Ahmad Saif. He published it 90 | on Github. 91 | I personally use this tool and I am happy with it :) 92 |
  • 93 |
  • 94 | Amir Aly from Delta Code created a bot that checks the API for load status and then it 95 | tweets (on @Egylectricity) 96 | and updates 97 | Egylectricity 98 | facebook page accordingly. 99 |
  • 100 |
101 |

102 |
103 | 104 |
105 | 106 |
107 | 108 | {% endblock %} 109 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Command/PrepDataForD3Command.php: -------------------------------------------------------------------------------- 1 | setName('power:prepdata') 21 | ->setDescription('Saves current power status to database'); 22 | } 23 | 24 | 25 | // 26 | protected function execute(InputInterface $input, OutputInterface $output) 27 | { 28 | try 29 | { 30 | $current_month = 'november'; 31 | 32 | // prepare today's data 33 | $repository = $this->getContainer()->get('doctrine')->getRepository('PowerGridBundle:Status'); 34 | 35 | 36 | // global values and configs 37 | $plus = $this->getContainer()->getParameter('gmt_as_number'); 38 | $web_dir_path = $this->getContainer()->getParameter('web_dir_path'); 39 | $tz = $this->getContainer()->getParameter('default_timezone');; 40 | 41 | $status_to_number = array( 42 | 'Safe' => 3, 43 | 'Warning' => 2, 44 | 'Danger' => 1, 45 | 'Unknown' => 1 46 | ); 47 | 48 | 49 | // Querying Today's data 50 | $today_date = new \DateTime('today midnight'); 51 | $yesterday = $today_date->setTimezone(new \DateTimeZone($tz))->modify('+' . $plus . ' hour')->modify('-1 day'); 52 | 53 | $today_query = $repository->createQueryBuilder('p') 54 | ->where('p.timestamp > :yesterday') 55 | ->setParameter('yesterday', $yesterday) 56 | ->orderBy('p.id', 'ASC') 57 | ->getQuery(); 58 | 59 | $records = $today_query->getResult(); 60 | 61 | $averaged_load_result = array(); 62 | foreach($records as $key => $object) 63 | { 64 | $day_number = intval($object->getTimestamp()->format('d')); 65 | $hour_number = intval($object->getTimestamp()->format('H')); 66 | $status_number = $status_to_number[$object->getStatus()]; 67 | 68 | $averaged_load_result[$day_number][$hour_number][1] = 0; 69 | $averaged_load_result[$day_number][$hour_number][2] = 0; 70 | $averaged_load_result[$day_number][$hour_number][3] = 0; 71 | 72 | $averaged_load_result[$day_number][$hour_number][$status_number]++; 73 | } 74 | 75 | $file_content = "day\thour\tvalue\n"; 76 | 77 | for($hour = 0; $hour <= count($averaged_load_result[$day_number]); $hour++) 78 | { 79 | if(isset($averaged_load_result[$day_number][$hour])) 80 | { 81 | $hour_value = array_search(max($averaged_load_result[$day_number][$hour]), $averaged_load_result[$day_number][$hour]); 82 | 83 | $file_content .= "1\t" . ($hour + 1) . "\t" . $hour_value . "\n"; 84 | } 85 | } 86 | 87 | $file_content .= "34\t10\t3\n"; 88 | $file_content .= "34\t11\t2\n"; 89 | $file_content .= "34\t12\t1\n"; 90 | 91 | print "Today Data\n"; 92 | print $file_content; 93 | print "\n\n"; 94 | 95 | $fs = new Filesystem(); 96 | 97 | try 98 | { 99 | $fs->dumpFile($web_dir_path . '/today.tsv', $file_content); 100 | } 101 | catch(IOExceptionInterface $e) 102 | { 103 | echo "An error occurred while creating your directory at " . $e->getPath(); 104 | } 105 | 106 | 107 | // Querying data for current month 108 | $first_day_in_month = new \DateTime('midnight first day of this month'); 109 | $first_day_in_month = $first_day_in_month->setTimezone(new \DateTimeZone($tz))->modify('+' . $plus . ' hour'); 110 | $query = $repository->createQueryBuilder('p') 111 | ->where('p.timestamp >= :first_day') 112 | ->setParameter('first_day', $first_day_in_month) 113 | ->orderBy('p.id', 'ASC') 114 | ->getQuery(); 115 | 116 | $records = $query->getResult(); 117 | 118 | $averaged_load_result = array(); 119 | foreach($records as $key => $object) 120 | { 121 | $day_number = intval($object->getTimestamp()->format('d')); 122 | $hour_number = intval($object->getTimestamp()->format('H')); 123 | $status_number = $status_to_number[$object->getStatus()]; 124 | 125 | $averaged_load_result[$day_number][$hour_number][1] = 0; 126 | $averaged_load_result[$day_number][$hour_number][2] = 0; 127 | $averaged_load_result[$day_number][$hour_number][3] = 0; 128 | 129 | $averaged_load_result[$day_number][$hour_number][$status_number]++; 130 | } 131 | 132 | $file_content = "day\thour\tvalue\n"; 133 | 134 | for($day_record = 1; $day_record <= count($averaged_load_result); $day_record++) 135 | { 136 | if(isset($averaged_load_result[$day_record])) 137 | { 138 | for($hour = 0; $hour <= count($averaged_load_result[$day_record]); $hour++) 139 | { 140 | if(isset($averaged_load_result[$day_record][$hour])) 141 | { 142 | $hour_value = array_search(max($averaged_load_result[$day_record][$hour]), $averaged_load_result[$day_record][$hour]); 143 | $file_content .= $day_record . "\t" . ($hour + 1) . "\t" . $hour_value . "\n"; 144 | } 145 | } 146 | } 147 | } 148 | 149 | // A dirty hack to make sure the domain has all possible values. 150 | $file_content .= "34\t10\t3\n"; 151 | $file_content .= "34\t11\t2\n"; 152 | $file_content .= "34\t12\t1\n"; 153 | 154 | $fs = new Filesystem(); 155 | 156 | try 157 | { 158 | $fs->dumpFile($web_dir_path . '/october.tsv', $file_content); 159 | } 160 | catch(IOExceptionInterface $e) 161 | { 162 | echo "An error occurred while creating your directory at " . $e->getPath(); 163 | } 164 | 165 | print "Month data\n"; 166 | print $file_content; 167 | 168 | } 169 | catch(\Exception $e) 170 | { 171 | $this->getContainer()->get('doctrine')->resetManager(); 172 | $output->writeln(sprintf('[%s] [error] %s', date('G:i:s'), $e->getMessage())); 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /web/config.php: -------------------------------------------------------------------------------- 1 | getFailedRequirements(); 20 | $minorProblems = $symfonyRequirements->getFailedRecommendations(); 21 | 22 | ?> 23 | 24 | 25 | 26 | 27 | 28 | Symfony Configuration 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 | 39 | 40 | 60 |
61 | 62 |
63 |
64 |
65 |

Welcome!

66 |

Welcome to your new Symfony project.

67 |

68 | This script will guide you through the basic configuration of your project. 69 | You can also do the same by editing the ‘app/config/parameters.yml’ file directly. 70 |

71 | 72 | 73 |

Major problems

74 |

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

75 |
    76 | 77 |
  1. getHelpHtml() ?>
  2. 78 | 79 |
80 | 81 | 82 | 83 |

Recommendations

84 |

85 | Additionally, toTo enhance your Symfony experience, 86 | it’s recommended that you fix the following: 87 |

88 |
    89 | 90 |
  1. getHelpHtml() ?>
  2. 91 | 92 |
93 | 94 | 95 | hasPhpIniConfigIssue()): ?> 96 |

* 97 | getPhpIniConfigPath()): ?> 98 | Changes to the php.ini file must be done in "getPhpIniConfigPath() ?>". 99 | 100 | To change settings, create a "php.ini". 101 | 102 |

103 | 104 | 105 | 106 |

Your configuration looks good to run Symfony.

107 | 108 | 109 | 118 |
119 |
120 |
121 |
Symfony Standard Edition
122 |
123 | 124 | 125 | -------------------------------------------------------------------------------- /app/Resources/views/base.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {% block fb %} {% endblock %} 13 | 14 | 15 | 16 | 17 | 18 | {% block title %} {% endblock %} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 97 | 98 | 99 | 100 | 101 |
102 |
103 | 113 |
114 |
115 | 116 | 117 |
118 | 119 | {% block content %}{% endblock %} 120 | 121 | 122 |
123 | 124 | 125 | 151 | 152 | 153 | 163 | 164 | 165 | 166 | 167 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Controller/DefaultController.php: -------------------------------------------------------------------------------- 1 | container->getParameter('default_timezone'); 14 | $plus = $this->container->getParameter('gmt_as_number'); 15 | $date = new \DateTime("today"); 16 | $date->setTimezone(new \DateTimeZone($tz))->modify('+' . $plus . ' hour'); 17 | 18 | $current_date = $date->format('l, F jS'); 19 | 20 | $template_vars = array( 21 | 'status' => $this->get('power_grid_service')->getStatus(), 22 | 'today' => $current_date, 23 | 'day_number' => $date->format('d'), 24 | 'month_number' => $date->format('m'), 25 | 'year_number' => $date->format('Y'), 26 | ); 27 | 28 | return $this->render('PowerGridBundle:Default:index.html.twig', $template_vars); 29 | } 30 | 31 | public function statusAction() 32 | { 33 | return new JsonResponse(array('status' => $this->get('power_grid_service')->getStatus())); 34 | } 35 | 36 | public function historyAction($year = '', $month = '') 37 | { 38 | if($year == '') 39 | { 40 | $year = date('Y'); 41 | } 42 | 43 | if($month == '') 44 | { 45 | $month = date('F'); 46 | } 47 | 48 | $month_date = new \Datetime($month . ' ' . $year); 49 | 50 | $d3_days = '['; 51 | 52 | $days_number = cal_days_in_month(CAL_GREGORIAN, $month_date->format('m'), $year); 53 | 54 | $start_date = $month_date->modify('first day of this month')->format('Y-m-d'); 55 | 56 | for($i = 0; $i < $days_number; $i++) 57 | { 58 | $date = strtotime(date("Y-m-d", strtotime($start_date)) . " $i day"); 59 | $d3_days .= '"' . date('l jS', $date) . '",'; 60 | } 61 | $d3_days .= '];'; 62 | 63 | $template_vars = array( 64 | 'month_name' => $month, 65 | 'd3_days' => $d3_days, 66 | 'year_number' => $year, 67 | 'month_number' => $month 68 | ); 69 | 70 | return $this->render('PowerGridBundle:Default:history.html.twig', $template_vars); 71 | } 72 | 73 | public function historytsvAction($year, $month, $day = '') 74 | { 75 | $repository = $this->getDoctrine()->getRepository('PowerGridBundle:Status'); 76 | 77 | // global values and configs 78 | $plus = $this->container->getParameter('gmt_as_number'); 79 | 80 | $tz = $this->container->getParameter('default_timezone');; 81 | 82 | $status_to_number = array( 83 | 'Safe' => 3, 84 | 'Warning' => 2, 85 | 'Danger' => 1, 86 | 'Unknown' => 4 87 | ); 88 | 89 | if(isset($day) && $day != '') 90 | { 91 | // Querying data for day 92 | $day_date = new \DateTime($year . '-' . $month . '-' . $day); 93 | $first_delimiter = $day_date->setTimezone(new \DateTimeZone($tz))->modify('+' . $plus . ' hour'); 94 | $last_delimiter = $first_delimiter; 95 | 96 | $day_loop = true; 97 | 98 | } 99 | else 100 | { 101 | // Querying data for month 102 | $first_delimiter = new \DateTime($year . '-' . $month . '-01'); 103 | $first_delimiter->modify('first day of this month'); 104 | 105 | $last_delimiter = new \DateTime($year . '-' . $month . '-01'); 106 | $last_delimiter->modify('last day of this month'); 107 | } 108 | 109 | // Create a query 110 | $query = $repository->createQueryBuilder('p') 111 | ->where('p.timestamp BETWEEN :starting AND :ending') 112 | ->setParameter('starting', $first_delimiter->format('Y-m-d 00:00:00')) 113 | ->setParameter('ending', $last_delimiter->format('Y-m-d 23:59:59')) 114 | ->orderBy('p.id', 'ASC') 115 | ->getQuery(); 116 | 117 | // Get the query result 118 | $records = $query->getResult(); 119 | 120 | // Initialize an array to process results 121 | $averaged_load_result = array(); 122 | 123 | // If we got any results process them 124 | if(!$records) 125 | { 126 | print 'No results exist!'; 127 | exit; 128 | } 129 | 130 | $tsv_output = "day\thour\tvalue\n"; 131 | 132 | foreach($records as $key => $object) 133 | { 134 | $day_number = intval($object->getTimestamp()->format('d')); 135 | $hour_number = intval($object->getTimestamp()->format('H')); 136 | $status_number = $status_to_number[$object->getStatus()]; 137 | 138 | $averaged_load_result[$day_number][$hour_number][1] = 0; 139 | $averaged_load_result[$day_number][$hour_number][2] = 0; 140 | $averaged_load_result[$day_number][$hour_number][3] = 0; 141 | $averaged_load_result[$day_number][$hour_number][4] = 0; 142 | 143 | $averaged_load_result[$day_number][$hour_number][$status_number]++; 144 | } 145 | 146 | // Prepare records for one day 147 | if(isset($day_loop) && $day_loop == true) 148 | { 149 | for($hour = 0; $hour <= count($averaged_load_result[$day_number]); $hour++) 150 | { 151 | if(isset($averaged_load_result[$day_number][$hour])) 152 | { 153 | $hour_value = array_search(max($averaged_load_result[$day_number][$hour]), $averaged_load_result[$day_number][$hour]); 154 | 155 | $tsv_output .= "1\t" . ($hour + 1) . "\t" . $hour_value . "\n"; 156 | } 157 | } 158 | } 159 | // prepare records for a month 160 | else 161 | { 162 | for($day_record = 1; $day_record <= count($averaged_load_result); $day_record++) 163 | { 164 | if(isset($averaged_load_result[$day_record])) 165 | { 166 | for($hour = 0; $hour <= count($averaged_load_result[$day_record]); $hour++) 167 | { 168 | if(isset($averaged_load_result[$day_record][$hour])) 169 | { 170 | $hour_value = array_search(max($averaged_load_result[$day_record][$hour]), $averaged_load_result[$day_record][$hour]); 171 | $tsv_output .= $day_record . "\t" . ($hour + 1) . "\t" . $hour_value . "\n"; 172 | } 173 | } 174 | } 175 | } 176 | } 177 | 178 | $tsv_output .= "34\t10\t4\n"; 179 | $tsv_output .= "34\t11\t3\n"; 180 | $tsv_output .= "34\t12\t2\n"; 181 | $tsv_output .= "34\t13\t1\n"; 182 | 183 | print $tsv_output; 184 | exit; 185 | } 186 | 187 | 188 | public function yearlyinfographicAction($year = '') 189 | { 190 | $template_vars = array(); 191 | return $this->render('PowerGridBundle:Default:infographic.html.twig', $template_vars); 192 | } 193 | 194 | public function apiAction() 195 | { 196 | return $this->render('PowerGridBundle:Default:api.html.twig'); 197 | } 198 | 199 | public function aboutAction() 200 | { 201 | return $this->render('PowerGridBundle:Default:about.html.twig'); 202 | } 203 | 204 | public function faqAction() 205 | { 206 | return $this->render('PowerGridBundle:Default:faq.html.twig'); 207 | } 208 | 209 | public function contactAction() 210 | { 211 | return $this->render('PowerGridBundle:Default:contact.html.twig'); 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Resources/views/Default/faq.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | 4 | {% block title %}FAQ | Grid Status Now{% endblock %} 5 | 6 | {% block fb %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% endblock %} 20 | 21 | {% block faq_active %} active{% endblock %} 22 | 23 | 24 | {% block content %} 25 |
26 |

Grid Status Now »

27 | 28 |

Frequently Asked Questions FAQ

29 | 30 |
31 | 32 |
33 | 34 |
35 | 36 |
37 |

Q. What is this project?

38 |

39 | This project exposes the current load status on the electric power grid in Egypt as a web service (or an API) so other developers can build other applications on top of it. 40 |

41 |
42 |

Q. Where does your data come from?

43 |

44 | This service parses the data on the 45 | Load Meter 46 | provided by The Egyptian Electric Utility and Consumer Protection Regulatory Agency 47 | (EGYPTERA) and exposes it. 48 |

49 | 50 |
51 |

Q. Is this data reliable?

52 |

53 | Most probably yes! But even if it is not, it is official, i.e. this is the officially publicly availed data by the government. 54 |

55 | 56 |
57 |

Q. Is this data region/location based?

58 |

59 | Unfortunately, no! We are limited by the data provided by EGYPTERA's load meter. 60 | They only provide the current load status across the whole Egypt's electric power grid. 61 |

62 | 63 |
64 |

Q. The power went out but the API shows the load status is green, why is that?

65 |

66 | This web service or API only provides the current load status on the electric grid in Egypt. 67 | It does not necessarily reflect power outages. It is more likely power will go out if the load meter shows the load is in the danger zone rather than the safe zone. But being in the safe zone does NOT mean power won't go out too! 68 |

69 | It is worth noting that power in Egypt, as many other things, doesn't always comply with logic! 70 |

71 | 72 |
73 |

Q. Ok, but why was the load status green during the long country wide power outage on Thursday, September 4th?

74 |

75 | Ironically, because power was out in most of the country, there was no electric consumption at all, thus there was no load whatsoever 76 | on the network and the load meter was as green as a forest! 77 |

78 | 79 |
80 |

Q. Do you keep track/history of the data/readings?

81 |

82 | Yes! We have a cron job that runs every ten minutes and saves a reading into our database. 83 | Those readings are used to populate the load distribution graphs in the history section 84 | of the website. 85 | 86 |

87 | 88 | We plan on expanding the API as soon as possible to expose this historical data as well. 89 |

90 | 91 |
92 |

Q. Is this service free?

93 |

94 | Yes! 95 |

96 | 97 |
98 |

Q. Will this service stay free?

99 |

100 | I have no idea! Hopefully, yes! 101 |

102 | 103 | 104 |
105 |

Q. Is the source code for this project available?

106 |

107 | Yes! You can find it on Github. 108 |

109 | 110 |
111 |

Q. Can I embed your load meter in my website?

112 |

113 | Unfortunately, not yet! However, there is a load meter developed by Kareem Kashwaa that you can embed. 114 |

115 | 116 |
117 |

Q. How is this project/service licensed?

118 |

119 | The source code for the scarping part of the project is licensed under a 120 | GNU General Public License Version 2.0. 121 | 122 | The API service doesn't have a license yet. 123 |

124 | 125 |
126 |

Q. Who is the creator/maintainer of this project?

127 |

128 | Hello, my name is Mosab Ahmad. I started working on this project after a post written by Tarek Amr intrigued me. There are also a couple of contributors to the project 129 | on Github. 130 |

131 | 132 |
133 |

Q. I have an idea/question/feedback, how can I contact the maintainer?

134 |

135 | You can email the maintainer on info@gridstatusnow.com. 136 |

137 | 138 | 139 |
140 | 141 |
142 | 143 |
144 | 145 | {% endblock %} 146 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Resources/views/Default/history.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '::base.html.twig' %} 2 | 3 | {% block title %}Load History In {{ month_name|title }}, {{ year_number }} | Grid Status Now{% endblock %} 4 | 5 | {% block fb %} 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | {% endblock %} 21 | 22 | {% block history_active %} active{% endblock %} 23 | 24 | {% block content %} 25 | 26 |
27 |
28 |
29 | 30 |

Grid Status Now »

31 | 32 |

Load History in {{ month_name|title }}, {{ year_number }}

33 | 34 |
35 | Legend : 36 | 37 | Normal 38 | 39 | 40 | Warning 41 | 42 | 43 | Danger 44 | 45 | 46 | Unknown 47 | 48 | 49 | 50 | 51 | 52 |
53 | 54 | {{ include('monthslist.html.twig') }} 55 | 56 | 57 | 58 | 154 |
155 | 156 |
157 | 158 | 159 |
160 | 161 |
162 |
163 | {% endblock %} 164 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | Symfony Standard Edition Upgrade 2 | ================================ 3 | 4 | From Symfony 2.0 to Symfony 2.1 5 | ------------------------------- 6 | 7 | ### Project Dependencies 8 | 9 | As of Symfony 2.1, project dependencies are managed by 10 | [Composer](http://getcomposer.org/): 11 | 12 | * The `bin/vendors` script can be removed as `composer.phar` does all the work 13 | now (it is recommended to install it globally on your machine). 14 | 15 | * The `deps` file need to be replaced with the `composer.json` one. 16 | 17 | * The `composer.lock` is the equivalent of the generated `deps.lock` file and 18 | it is automatically generated by Composer. 19 | 20 | Download the default 21 | [`composer.json`](https://raw.github.com/symfony/symfony-standard/2.1/composer.json) 22 | and 23 | [`composer.lock`](https://raw.github.com/symfony/symfony-standard/2.1/composer.lock) 24 | files for Symfony 2.1 and put them into the main directory of your project. If 25 | you have customized your `deps` file, move the added dependencies to the 26 | `composer.json` file (many bundles and PHP libraries are already available as 27 | Composer packages -- search for them on [Packagist](http://packagist.org/)). 28 | 29 | Remove your current `vendor` directory. 30 | 31 | Finally, run Composer: 32 | 33 | $ composer.phar install 34 | 35 | Note: You must complete the upgrade steps below so composer can successfully generate the autoload files. 36 | 37 | ### `app/autoload.php` 38 | 39 | The default `autoload.php` reads as follows (it has been simplified a lot as 40 | autoloading for libraries and bundles declared in your `composer.json` file is 41 | automatically managed by the Composer autoloader): 42 | 43 | add('', __DIR__.'/../vendor/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs'); 54 | } 55 | 56 | AnnotationRegistry::registerLoader(array($loader, 'loadClass')); 57 | 58 | return $loader; 59 | 60 | ### `app/config/config.yml` 61 | 62 | The `framework.charset` setting must be removed. If you are not using `UTF-8` 63 | for your application, override the `getCharset()` method in your `AppKernel` 64 | class instead: 65 | 66 | class AppKernel extends Kernel 67 | { 68 | public function getCharset() 69 | { 70 | return 'ISO-8859-1'; 71 | } 72 | 73 | // ... 74 | } 75 | 76 | You might want to add the new `strict_requirements` parameter to 77 | `framework.router` (it avoids fatal errors in the production environment when 78 | a link cannot be generated): 79 | 80 | framework: 81 | router: 82 | strict_requirements: "%kernel.debug%" 83 | 84 | You can even disable the requirements check on production with `null` as you should 85 | know that the parameters for URL generation always pass the requirements, e.g. by 86 | validating them beforehand. This additionally enhances performance. See 87 | [config_prod.yml](https://github.com/symfony/symfony-standard/blob/master/app/config/config_prod.yml). 88 | 89 | The `default_locale` parameter is now a setting of the main `framework` 90 | configuration (it was under the `framework.session` in 2.0): 91 | 92 | framework: 93 | default_locale: "%locale%" 94 | 95 | The `auto_start` setting under `framework.session` must be removed as it is 96 | not used anymore (the session is now always started on-demand). If 97 | `auto_start` was the only setting under the `framework.session` entry, don't 98 | remove it entirely, but set its value to `~` (`~` means `null` in YAML) 99 | instead: 100 | 101 | framework: 102 | session: ~ 103 | 104 | The `trust_proxy_headers` setting was added in the default configuration file 105 | (as it should be set to `true` when you install your application behind a 106 | reverse proxy): 107 | 108 | framework: 109 | trust_proxy_headers: false 110 | 111 | An empty `bundles` entry was added to the `assetic` configuration: 112 | 113 | assetic: 114 | bundles: [] 115 | 116 | The default `swiftmailer` configuration now has the `spool` setting configured 117 | to the `memory` type to defer email sending after the response is sent to the 118 | user (recommended for better end-user performance): 119 | 120 | swiftmailer: 121 | spool: { type: memory } 122 | 123 | The `jms_security_extra` configuration was moved to the `security.yml` 124 | configuration file. 125 | 126 | ### `app/config/config_dev.yml` 127 | 128 | An example of how to send all emails to a unique address was added: 129 | 130 | #swiftmailer: 131 | # delivery_address: me@example.com 132 | 133 | ### `app/config/config_test.yml` 134 | 135 | The `storage_id` setting must be changed to `session.storage.mock_file`: 136 | 137 | framework: 138 | session: 139 | storage_id: session.storage.mock_file 140 | 141 | ### `app/config/parameters.ini` 142 | 143 | The file has been converted to a YAML file which reads as follows: 144 | 145 | parameters: 146 | database_driver: pdo_mysql 147 | database_host: localhost 148 | database_port: ~ 149 | database_name: symfony 150 | database_user: root 151 | database_password: ~ 152 | 153 | mailer_transport: smtp 154 | mailer_host: localhost 155 | mailer_user: ~ 156 | mailer_password: ~ 157 | 158 | locale: en 159 | secret: ThisTokenIsNotSoSecretChangeIt 160 | 161 | Note that if you convert your parameters file to YAML, you must also change 162 | its reference in `app/config/config.yml`. 163 | 164 | ### `app/config/routing_dev.yml` 165 | 166 | The `_assetic` entry was removed: 167 | 168 | #_assetic: 169 | # resource: . 170 | # type: assetic 171 | 172 | ### `app/config/security.yml` 173 | 174 | Under `security.access_control`, the default rule for internal routes was changed: 175 | 176 | security: 177 | access_control: 178 | #- { path: ^/_internal/secure, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 } 179 | 180 | Under `security.providers`, the `in_memory` example was updated to the following: 181 | 182 | security: 183 | providers: 184 | in_memory: 185 | memory: 186 | users: 187 | user: { password: userpass, roles: [ 'ROLE_USER' ] } 188 | admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] } 189 | 190 | ### `app/AppKernel.php` 191 | 192 | The following bundles have been added to the list of default registered bundles: 193 | 194 | new JMS\AopBundle\JMSAopBundle(), 195 | new JMS\DiExtraBundle\JMSDiExtraBundle($this), 196 | 197 | You must also rename the DoctrineBundle from: 198 | 199 | new Symfony\Bundle\DoctrineBundle\DoctrineBundle(), 200 | 201 | to: 202 | 203 | new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), 204 | 205 | ### `web/app.php` 206 | 207 | The default `web/app.php` file now reads as follows: 208 | 209 | register(true); 222 | */ 223 | 224 | require_once __DIR__.'/../app/AppKernel.php'; 225 | //require_once __DIR__.'/../app/AppCache.php'; 226 | 227 | $kernel = new AppKernel('prod', false); 228 | $kernel->loadClassCache(); 229 | //$kernel = new AppCache($kernel); 230 | $request = Request::createFromGlobals(); 231 | $response = $kernel->handle($request); 232 | $response->send(); 233 | $kernel->terminate($request, $response); 234 | 235 | ### `web/app_dev.php` 236 | 237 | The default `web/app_dev.php` file now reads as follows: 238 | 239 | loadClassCache(); 265 | $request = Request::createFromGlobals(); 266 | $response = $kernel->handle($request); 267 | $response->send(); 268 | $kernel->terminate($request, $response); 269 | -------------------------------------------------------------------------------- /src/PowerGrid/PowerGridBundle/Resources/views/Default/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | {% if status == 'Danger' %} 4 | {% set status_class = 'danger' %} 5 | {% set status_message = 'Danger Zone' %} 6 | {% elseif status == 'Warning' %} 7 | {% set status_class = 'warning' %} 8 | {% set status_message = 'Warning Zone' %} 9 | {% elseif status == 'Safe' %} 10 | {% set status_class = 'success' %} 11 | {% set status_message = 'Safe Zone' %} 12 | {% else %} 13 | {% set status_class = 'danger' %} 14 | {% set status_message = 'Unknown Status. Source seems to be down!' %} 15 | {% endif %} 16 | 17 | {% block title %}Grid Status Now | Egypt's Power Grid Load Status As A Web Service{% endblock %} 18 | 19 | {% block fb %} 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | {% endblock %} 36 | 37 | {% block home_active %} active{% endblock %} 38 | 39 | {% block content %} 40 |
41 |

Grid Status Now

42 | 43 |

Egypt's Power Grid Load Status As A Web Service

44 | 45 |
46 | 47 |
48 |
49 |
50 |

51 |

Load on Egypt's electric power grid is in the*:

52 | 54 | {{ status_message }} 55 | 56 |

57 | 58 |

59 | 60 | *According to The Egyptian Electric Utility and Consumer 61 | Protection Regulatory Agency 62 | (EGYPTERA). 63 | 64 |

65 | 66 |
67 | 68 |

Power Load Distribution Throughout {{ today }}

69 |

70 | 71 |

72 |

73 |
74 | Legend : 75 | 76 | Normal 77 | 78 | 79 | Warning 80 | 81 | 82 | Danger 83 | 84 |

85 |

86 | 87 |

88 | 89 | Each block stands for an hour of the day starting at 12 am and finishing at 12 am the next day. 90 | Each block's color represents how the power load was most of that hour with a color code, 91 | green for safe, yellow for warning and red for danger. 92 | 93 |

94 |

95 |
96 | 97 | {{ include('monthslist.html.twig') }} 98 | 99 |
100 |

Developers

101 | 102 |

103 | Are you a software developer looking to integrate this data into your application? 104 | This project provides a web service. Head to the API section for 105 | more information. 106 |

107 | 108 |
109 |

Disclaimer

110 | 111 |

112 | This service is created and its code is open sourced in the hope that it will be useful, 113 | but WITHOUT ANY WARRANTY; without even the implied warranty of 114 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 115 |

116 |
117 | 118 |
119 | 120 |
121 | 122 | 212 | {% endblock %} 213 | -------------------------------------------------------------------------------- /gpl-2.0.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /app/SymfonyRequirements.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /* 13 | * Users of PHP 5.2 should be able to run the requirements checks. 14 | * This is why the file and all classes must be compatible with PHP 5.2+ 15 | * (e.g. not using namespaces and closures). 16 | * 17 | * ************** CAUTION ************** 18 | * 19 | * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of 20 | * the installation/update process. The original file resides in the 21 | * SensioDistributionBundle. 22 | * 23 | * ************** CAUTION ************** 24 | */ 25 | 26 | /** 27 | * Represents a single PHP requirement, e.g. an installed extension. 28 | * It can be a mandatory requirement or an optional recommendation. 29 | * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration. 30 | * 31 | * @author Tobias Schultze 32 | */ 33 | class Requirement 34 | { 35 | private $fulfilled; 36 | private $testMessage; 37 | private $helpText; 38 | private $helpHtml; 39 | private $optional; 40 | 41 | /** 42 | * Constructor that initializes the requirement. 43 | * 44 | * @param Boolean $fulfilled Whether the requirement is fulfilled 45 | * @param string $testMessage The message for testing the requirement 46 | * @param string $helpHtml The help text formatted in HTML for resolving the problem 47 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 48 | * @param Boolean $optional Whether this is only an optional recommendation not a mandatory requirement 49 | */ 50 | public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false) 51 | { 52 | $this->fulfilled = (Boolean) $fulfilled; 53 | $this->testMessage = (string) $testMessage; 54 | $this->helpHtml = (string) $helpHtml; 55 | $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText; 56 | $this->optional = (Boolean) $optional; 57 | } 58 | 59 | /** 60 | * Returns whether the requirement is fulfilled. 61 | * 62 | * @return Boolean true if fulfilled, otherwise false 63 | */ 64 | public function isFulfilled() 65 | { 66 | return $this->fulfilled; 67 | } 68 | 69 | /** 70 | * Returns the message for testing the requirement. 71 | * 72 | * @return string The test message 73 | */ 74 | public function getTestMessage() 75 | { 76 | return $this->testMessage; 77 | } 78 | 79 | /** 80 | * Returns the help text for resolving the problem 81 | * 82 | * @return string The help text 83 | */ 84 | public function getHelpText() 85 | { 86 | return $this->helpText; 87 | } 88 | 89 | /** 90 | * Returns the help text formatted in HTML. 91 | * 92 | * @return string The HTML help 93 | */ 94 | public function getHelpHtml() 95 | { 96 | return $this->helpHtml; 97 | } 98 | 99 | /** 100 | * Returns whether this is only an optional recommendation and not a mandatory requirement. 101 | * 102 | * @return Boolean true if optional, false if mandatory 103 | */ 104 | public function isOptional() 105 | { 106 | return $this->optional; 107 | } 108 | } 109 | 110 | /** 111 | * Represents a PHP requirement in form of a php.ini configuration. 112 | * 113 | * @author Tobias Schultze 114 | */ 115 | class PhpIniRequirement extends Requirement 116 | { 117 | /** 118 | * Constructor that initializes the requirement. 119 | * 120 | * @param string $cfgName The configuration name used for ini_get() 121 | * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false, 122 | or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement 123 | * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. 124 | This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. 125 | Example: You require a config to be true but PHP later removes this config and defaults it to true internally. 126 | * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived) 127 | * @param string|null $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived) 128 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 129 | * @param Boolean $optional Whether this is only an optional recommendation not a mandatory requirement 130 | */ 131 | public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false) 132 | { 133 | $cfgValue = ini_get($cfgName); 134 | 135 | if (is_callable($evaluation)) { 136 | if (null === $testMessage || null === $helpHtml) { 137 | throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.'); 138 | } 139 | 140 | $fulfilled = call_user_func($evaluation, $cfgValue); 141 | } else { 142 | if (null === $testMessage) { 143 | $testMessage = sprintf('%s %s be %s in php.ini', 144 | $cfgName, 145 | $optional ? 'should' : 'must', 146 | $evaluation ? 'enabled' : 'disabled' 147 | ); 148 | } 149 | 150 | if (null === $helpHtml) { 151 | $helpHtml = sprintf('Set %s to %s in php.ini*.', 152 | $cfgName, 153 | $evaluation ? 'on' : 'off' 154 | ); 155 | } 156 | 157 | $fulfilled = $evaluation == $cfgValue; 158 | } 159 | 160 | parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional); 161 | } 162 | } 163 | 164 | /** 165 | * A RequirementCollection represents a set of Requirement instances. 166 | * 167 | * @author Tobias Schultze 168 | */ 169 | class RequirementCollection implements IteratorAggregate 170 | { 171 | private $requirements = array(); 172 | 173 | /** 174 | * Gets the current RequirementCollection as an Iterator. 175 | * 176 | * @return Traversable A Traversable interface 177 | */ 178 | public function getIterator() 179 | { 180 | return new ArrayIterator($this->requirements); 181 | } 182 | 183 | /** 184 | * Adds a Requirement. 185 | * 186 | * @param Requirement $requirement A Requirement instance 187 | */ 188 | public function add(Requirement $requirement) 189 | { 190 | $this->requirements[] = $requirement; 191 | } 192 | 193 | /** 194 | * Adds a mandatory requirement. 195 | * 196 | * @param Boolean $fulfilled Whether the requirement is fulfilled 197 | * @param string $testMessage The message for testing the requirement 198 | * @param string $helpHtml The help text formatted in HTML for resolving the problem 199 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 200 | */ 201 | public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null) 202 | { 203 | $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false)); 204 | } 205 | 206 | /** 207 | * Adds an optional recommendation. 208 | * 209 | * @param Boolean $fulfilled Whether the recommendation is fulfilled 210 | * @param string $testMessage The message for testing the recommendation 211 | * @param string $helpHtml The help text formatted in HTML for resolving the problem 212 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 213 | */ 214 | public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null) 215 | { 216 | $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true)); 217 | } 218 | 219 | /** 220 | * Adds a mandatory requirement in form of a php.ini configuration. 221 | * 222 | * @param string $cfgName The configuration name used for ini_get() 223 | * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false, 224 | or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement 225 | * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. 226 | This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. 227 | Example: You require a config to be true but PHP later removes this config and defaults it to true internally. 228 | * @param string $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived) 229 | * @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) 230 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 231 | */ 232 | public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) 233 | { 234 | $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false)); 235 | } 236 | 237 | /** 238 | * Adds an optional recommendation in form of a php.ini configuration. 239 | * 240 | * @param string $cfgName The configuration name used for ini_get() 241 | * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false, 242 | or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement 243 | * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. 244 | This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. 245 | Example: You require a config to be true but PHP later removes this config and defaults it to true internally. 246 | * @param string $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived) 247 | * @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) 248 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 249 | */ 250 | public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) 251 | { 252 | $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true)); 253 | } 254 | 255 | /** 256 | * Adds a requirement collection to the current set of requirements. 257 | * 258 | * @param RequirementCollection $collection A RequirementCollection instance 259 | */ 260 | public function addCollection(RequirementCollection $collection) 261 | { 262 | $this->requirements = array_merge($this->requirements, $collection->all()); 263 | } 264 | 265 | /** 266 | * Returns both requirements and recommendations. 267 | * 268 | * @return array Array of Requirement instances 269 | */ 270 | public function all() 271 | { 272 | return $this->requirements; 273 | } 274 | 275 | /** 276 | * Returns all mandatory requirements. 277 | * 278 | * @return array Array of Requirement instances 279 | */ 280 | public function getRequirements() 281 | { 282 | $array = array(); 283 | foreach ($this->requirements as $req) { 284 | if (!$req->isOptional()) { 285 | $array[] = $req; 286 | } 287 | } 288 | 289 | return $array; 290 | } 291 | 292 | /** 293 | * Returns the mandatory requirements that were not met. 294 | * 295 | * @return array Array of Requirement instances 296 | */ 297 | public function getFailedRequirements() 298 | { 299 | $array = array(); 300 | foreach ($this->requirements as $req) { 301 | if (!$req->isFulfilled() && !$req->isOptional()) { 302 | $array[] = $req; 303 | } 304 | } 305 | 306 | return $array; 307 | } 308 | 309 | /** 310 | * Returns all optional recommendations. 311 | * 312 | * @return array Array of Requirement instances 313 | */ 314 | public function getRecommendations() 315 | { 316 | $array = array(); 317 | foreach ($this->requirements as $req) { 318 | if ($req->isOptional()) { 319 | $array[] = $req; 320 | } 321 | } 322 | 323 | return $array; 324 | } 325 | 326 | /** 327 | * Returns the recommendations that were not met. 328 | * 329 | * @return array Array of Requirement instances 330 | */ 331 | public function getFailedRecommendations() 332 | { 333 | $array = array(); 334 | foreach ($this->requirements as $req) { 335 | if (!$req->isFulfilled() && $req->isOptional()) { 336 | $array[] = $req; 337 | } 338 | } 339 | 340 | return $array; 341 | } 342 | 343 | /** 344 | * Returns whether a php.ini configuration is not correct. 345 | * 346 | * @return Boolean php.ini configuration problem? 347 | */ 348 | public function hasPhpIniConfigIssue() 349 | { 350 | foreach ($this->requirements as $req) { 351 | if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) { 352 | return true; 353 | } 354 | } 355 | 356 | return false; 357 | } 358 | 359 | /** 360 | * Returns the PHP configuration file (php.ini) path. 361 | * 362 | * @return string|false php.ini file path 363 | */ 364 | public function getPhpIniConfigPath() 365 | { 366 | return get_cfg_var('cfg_file_path'); 367 | } 368 | } 369 | 370 | /** 371 | * This class specifies all requirements and optional recommendations that 372 | * are necessary to run the Symfony Standard Edition. 373 | * 374 | * @author Tobias Schultze 375 | * @author Fabien Potencier 376 | */ 377 | class SymfonyRequirements extends RequirementCollection 378 | { 379 | const REQUIRED_PHP_VERSION = '5.3.3'; 380 | 381 | /** 382 | * Constructor that initializes the requirements. 383 | */ 384 | public function __construct() 385 | { 386 | /* mandatory requirements follow */ 387 | 388 | $installedPhpVersion = phpversion(); 389 | 390 | $this->addRequirement( 391 | version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>='), 392 | sprintf('PHP version must be at least %s (%s installed)', self::REQUIRED_PHP_VERSION, $installedPhpVersion), 393 | sprintf('You are running PHP version "%s", but Symfony needs at least PHP "%s" to run. 394 | Before using Symfony, upgrade your PHP installation, preferably to the latest version.', 395 | $installedPhpVersion, self::REQUIRED_PHP_VERSION), 396 | sprintf('Install PHP %s or newer (installed version is %s)', self::REQUIRED_PHP_VERSION, $installedPhpVersion) 397 | ); 398 | 399 | $this->addRequirement( 400 | version_compare($installedPhpVersion, '5.3.16', '!='), 401 | 'PHP version must not be 5.3.16 as Symfony won\'t work properly with it', 402 | 'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)' 403 | ); 404 | 405 | $this->addRequirement( 406 | is_dir(__DIR__.'/../vendor/composer'), 407 | 'Vendor libraries must be installed', 408 | 'Vendor libraries are missing. Install composer following instructions from http://getcomposer.org/. ' . 409 | 'Then run "php composer.phar install" to install them.' 410 | ); 411 | 412 | $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache'; 413 | 414 | $this->addRequirement( 415 | is_writable($cacheDir), 416 | 'app/cache/ or var/cache/ directory must be writable', 417 | 'Change the permissions of either "app/cache/" or "var/cache/" directory so that the web server can write into it.' 418 | ); 419 | 420 | $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs'; 421 | 422 | $this->addRequirement( 423 | is_writable($logsDir), 424 | 'app/logs/ or var/logs/ directory must be writable', 425 | 'Change the permissions of either "app/logs/" or "var/logs/" directory so that the web server can write into it.' 426 | ); 427 | 428 | $this->addPhpIniRequirement( 429 | 'date.timezone', true, false, 430 | 'date.timezone setting must be set', 431 | 'Set the "date.timezone" setting in php.ini* (like Europe/Paris).' 432 | ); 433 | 434 | if (version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>=')) { 435 | $timezones = array(); 436 | foreach (DateTimeZone::listAbbreviations() as $abbreviations) { 437 | foreach ($abbreviations as $abbreviation) { 438 | $timezones[$abbreviation['timezone_id']] = true; 439 | } 440 | } 441 | 442 | $this->addRequirement( 443 | isset($timezones[date_default_timezone_get()]), 444 | sprintf('Configured default timezone "%s" must be supported by your installation of PHP', date_default_timezone_get()), 445 | 'Your default timezone is not supported by PHP. Check for typos in your php.ini file and have a look at the list of deprecated timezones at http://php.net/manual/en/timezones.others.php.' 446 | ); 447 | } 448 | 449 | $this->addRequirement( 450 | function_exists('json_encode'), 451 | 'json_encode() must be available', 452 | 'Install and enable the JSON extension.' 453 | ); 454 | 455 | $this->addRequirement( 456 | function_exists('session_start'), 457 | 'session_start() must be available', 458 | 'Install and enable the session extension.' 459 | ); 460 | 461 | $this->addRequirement( 462 | function_exists('ctype_alpha'), 463 | 'ctype_alpha() must be available', 464 | 'Install and enable the ctype extension.' 465 | ); 466 | 467 | $this->addRequirement( 468 | function_exists('token_get_all'), 469 | 'token_get_all() must be available', 470 | 'Install and enable the Tokenizer extension.' 471 | ); 472 | 473 | $this->addRequirement( 474 | function_exists('simplexml_import_dom'), 475 | 'simplexml_import_dom() must be available', 476 | 'Install and enable the SimpleXML extension.' 477 | ); 478 | 479 | if (function_exists('apc_store') && ini_get('apc.enabled')) { 480 | if (version_compare($installedPhpVersion, '5.4.0', '>=')) { 481 | $this->addRequirement( 482 | version_compare(phpversion('apc'), '3.1.13', '>='), 483 | 'APC version must be at least 3.1.13 when using PHP 5.4', 484 | 'Upgrade your APC extension (3.1.13+).' 485 | ); 486 | } else { 487 | $this->addRequirement( 488 | version_compare(phpversion('apc'), '3.0.17', '>='), 489 | 'APC version must be at least 3.0.17', 490 | 'Upgrade your APC extension (3.0.17+).' 491 | ); 492 | } 493 | } 494 | 495 | $this->addPhpIniRequirement('detect_unicode', false); 496 | 497 | if (extension_loaded('suhosin')) { 498 | $this->addPhpIniRequirement( 499 | 'suhosin.executor.include.whitelist', 500 | create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'), 501 | false, 502 | 'suhosin.executor.include.whitelist must be configured correctly in php.ini', 503 | 'Add "phar" to suhosin.executor.include.whitelist in php.ini*.' 504 | ); 505 | } 506 | 507 | if (extension_loaded('xdebug')) { 508 | $this->addPhpIniRequirement( 509 | 'xdebug.show_exception_trace', false, true 510 | ); 511 | 512 | $this->addPhpIniRequirement( 513 | 'xdebug.scream', false, true 514 | ); 515 | 516 | $this->addPhpIniRecommendation( 517 | 'xdebug.max_nesting_level', 518 | create_function('$cfgValue', 'return $cfgValue > 100;'), 519 | true, 520 | 'xdebug.max_nesting_level should be above 100 in php.ini', 521 | 'Set "xdebug.max_nesting_level" to e.g. "250" in php.ini* to stop Xdebug\'s infinite recursion protection erroneously throwing a fatal error in your project.' 522 | ); 523 | } 524 | 525 | $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null; 526 | 527 | $this->addRequirement( 528 | null !== $pcreVersion, 529 | 'PCRE extension must be available', 530 | 'Install the PCRE extension (version 8.0+).' 531 | ); 532 | 533 | /* optional recommendations follow */ 534 | 535 | $this->addRecommendation( 536 | file_get_contents(__FILE__) === file_get_contents(__DIR__.'/../vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Resources/skeleton/app/SymfonyRequirements.php'), 537 | 'Requirements file should be up-to-date', 538 | 'Your requirements file is outdated. Run composer install and re-check your configuration.' 539 | ); 540 | 541 | $this->addRecommendation( 542 | version_compare($installedPhpVersion, '5.3.4', '>='), 543 | 'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions', 544 | '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.' 545 | ); 546 | 547 | $this->addRecommendation( 548 | version_compare($installedPhpVersion, '5.3.8', '>='), 549 | 'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156', 550 | 'Install PHP 5.3.8 or newer if your project uses annotations.' 551 | ); 552 | 553 | $this->addRecommendation( 554 | version_compare($installedPhpVersion, '5.4.0', '!='), 555 | 'You should not use PHP 5.4.0 due to the PHP bug #61453', 556 | '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.' 557 | ); 558 | 559 | $this->addRecommendation( 560 | version_compare($installedPhpVersion, '5.4.11', '>='), 561 | '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)', 562 | 'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.' 563 | ); 564 | 565 | $this->addRecommendation( 566 | (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<')) 567 | || 568 | version_compare($installedPhpVersion, '5.4.8', '>='), 569 | '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', 570 | 'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.' 571 | ); 572 | 573 | if (null !== $pcreVersion) { 574 | $this->addRecommendation( 575 | $pcreVersion >= 8.0, 576 | sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion), 577 | 'PCRE 8.0+ is preconfigured in PHP since 5.3.2 but you are using an outdated version of it. Symfony probably works anyway but it is recommended to upgrade your PCRE extension.' 578 | ); 579 | } 580 | 581 | $this->addRecommendation( 582 | class_exists('DomDocument'), 583 | 'PHP-XML module should be installed', 584 | 'Install and enable the PHP-XML module.' 585 | ); 586 | 587 | $this->addRecommendation( 588 | function_exists('mb_strlen'), 589 | 'mb_strlen() should be available', 590 | 'Install and enable the mbstring extension.' 591 | ); 592 | 593 | $this->addRecommendation( 594 | function_exists('iconv'), 595 | 'iconv() should be available', 596 | 'Install and enable the iconv extension.' 597 | ); 598 | 599 | $this->addRecommendation( 600 | function_exists('utf8_decode'), 601 | 'utf8_decode() should be available', 602 | 'Install and enable the XML extension.' 603 | ); 604 | 605 | $this->addRecommendation( 606 | function_exists('filter_var'), 607 | 'filter_var() should be available', 608 | 'Install and enable the filter extension.' 609 | ); 610 | 611 | if (!defined('PHP_WINDOWS_VERSION_BUILD')) { 612 | $this->addRecommendation( 613 | function_exists('posix_isatty'), 614 | 'posix_isatty() should be available', 615 | 'Install and enable the php_posix extension (used to colorize the CLI output).' 616 | ); 617 | } 618 | 619 | $this->addRecommendation( 620 | class_exists('Locale'), 621 | 'intl extension should be available', 622 | 'Install and enable the intl extension (used for validators).' 623 | ); 624 | 625 | if (class_exists('Collator')) { 626 | $this->addRecommendation( 627 | null !== new Collator('fr_FR'), 628 | 'intl extension should be correctly configured', 629 | 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.' 630 | ); 631 | } 632 | 633 | if (class_exists('Locale')) { 634 | if (defined('INTL_ICU_VERSION')) { 635 | $version = INTL_ICU_VERSION; 636 | } else { 637 | $reflector = new ReflectionExtension('intl'); 638 | 639 | ob_start(); 640 | $reflector->info(); 641 | $output = strip_tags(ob_get_clean()); 642 | 643 | preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches); 644 | $version = $matches[1]; 645 | } 646 | 647 | $this->addRecommendation( 648 | version_compare($version, '4.0', '>='), 649 | 'intl ICU version should be at least 4+', 650 | 'Upgrade your intl extension with a newer ICU version (4+).' 651 | ); 652 | } 653 | 654 | $accelerator = 655 | (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) 656 | || 657 | (extension_loaded('apc') && ini_get('apc.enabled')) 658 | || 659 | (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable')) 660 | || 661 | (extension_loaded('Zend OPcache') && ini_get('opcache.enable')) 662 | || 663 | (extension_loaded('xcache') && ini_get('xcache.cacher')) 664 | || 665 | (extension_loaded('wincache') && ini_get('wincache.ocenabled')) 666 | ; 667 | 668 | $this->addRecommendation( 669 | $accelerator, 670 | 'a PHP accelerator should be installed', 671 | 'Install and/or enable a PHP accelerator (highly recommended).' 672 | ); 673 | 674 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { 675 | $this->addPhpIniRecommendation( 676 | 'realpath_cache_size', 677 | create_function('$cfgValue', 'return (int) $cfgValue > 1000;'), 678 | false, 679 | 'realpath_cache_size should be above 1024 in php.ini', 680 | 'Set "realpath_cache_size" to e.g. "1024" in php.ini* to improve performance on windows.' 681 | ); 682 | } 683 | 684 | $this->addPhpIniRecommendation('short_open_tag', false); 685 | 686 | $this->addPhpIniRecommendation('magic_quotes_gpc', false, true); 687 | 688 | $this->addPhpIniRecommendation('register_globals', false, true); 689 | 690 | $this->addPhpIniRecommendation('session.auto_start', false); 691 | 692 | $this->addRecommendation( 693 | class_exists('PDO'), 694 | 'PDO should be installed', 695 | 'Install PDO (mandatory for Doctrine).' 696 | ); 697 | 698 | if (class_exists('PDO')) { 699 | $drivers = PDO::getAvailableDrivers(); 700 | $this->addRecommendation( 701 | count($drivers) > 0, 702 | sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'), 703 | 'Install PDO drivers (mandatory for Doctrine).' 704 | ); 705 | } 706 | } 707 | } 708 | --------------------------------------------------------------------------------