X-Git-Url: https://git.rapsys.eu/airbundle/blobdiff_plain/1cb9165e95db75354b5681b7749fcdf9133afd5a..8e9a8cfed083ec7e7410aab5aadcae945cdfd9e8:/Command/WeatherCommand.php diff --git a/Command/WeatherCommand.php b/Command/WeatherCommand.php index 00f922c..c6fe6fc 100644 --- a/Command/WeatherCommand.php +++ b/Command/WeatherCommand.php @@ -1,12 +1,24 @@ - + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Rapsys\AirBundle\Command; use Doctrine\Bundle\DoctrineBundle\Command\DoctrineCommand; +use Doctrine\Persistence\ManagerRegistry; + use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Filesystem\Exception\IOExceptionInterface; +use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Filesystem; + use Rapsys\AirBundle\Entity\Session; class WeatherCommand extends DoctrineCommand { @@ -33,9 +45,14 @@ class WeatherCommand extends DoctrineCommand { //Hourly uri 'hourly' => [ 75001 => 'https://www.accuweather.com/en/fr/paris-01-louvre/75001/hourly-weather-forecast/179142_pc?day=', + 75004 => 'https://www.accuweather.com/en/fr/paris-04-hotel-de-ville/75004/hourly-weather-forecast/179145_pc?day=', 75005 => 'https://www.accuweather.com/en/fr/paris-05-pantheon/75005/hourly-weather-forecast/179146_pc?day=', + 75006 => 'https://www.accuweather.com/fr/fr/paris-06-luxembourg/75006/hourly-weather-forecast/179147_pc?day=', 75007 => 'https://www.accuweather.com/en/fr/paris-07-palais-bourbon/75007/hourly-weather-forecast/179148_pc?day=', 75009 => 'https://www.accuweather.com/en/fr/paris-09-opera/75009/hourly-weather-forecast/179150_pc?day=', + 75010 => 'https://www.accuweather.com/en/fr/paris-10-entrepot/75010/hourly-weather-forecast/179151_pc?day=', + 75012 => 'https://www.accuweather.com/en/fr/paris-12-reuilly/75012/hourly-weather-forecast/179153_pc?day=', + 75013 => 'https://www.accuweather.com/en/fr/paris-13-gobelins/75013/hourly-weather-forecast/179154_pc?day=', 75015 => 'https://www.accuweather.com/en/fr/paris-15-vaugirard/75015/hourly-weather-forecast/179156_pc?day=', 75019 => 'https://www.accuweather.com/en/fr/paris-19-buttes-chaumont/75019/hourly-weather-forecast/179160_pc?day=', 75116 => 'https://www.accuweather.com/en/fr/paris-16-passy/75116/hourly-weather-forecast/179246_pc?day=' @@ -43,9 +60,14 @@ class WeatherCommand extends DoctrineCommand { //Daily uri 'daily' => [ 75001 => 'https://www.accuweather.com/en/fr/paris-01-louvre/75001/daily-weather-forecast/179142_pc', + 75004 => 'https://www.accuweather.com/en/fr/paris-04-hotel-de-ville/75004/daily-weather-forecast/179145_pc', 75005 => 'https://www.accuweather.com/en/fr/paris-05-pantheon/75005/daily-weather-forecast/179146_pc', + 75006 => 'https://www.accuweather.com/fr/fr/paris-06-luxembourg/75006/daily-weather-forecast/179147_pc', 75007 => 'https://www.accuweather.com/en/fr/paris-07-palais-bourbon/75007/daily-weather-forecast/179148_pc', 75009 => 'https://www.accuweather.com/en/fr/paris-09-opera/75009/daily-weather-forecast/179150_pc', + 75010 => 'https://www.accuweather.com/en/fr/paris-10-entrepot/75010/daily-weather-forecast/179151_pc', + 75012 => 'https://www.accuweather.com/en/fr/paris-12-reuilly/75012/daily-weather-forecast/179153_pc', + 75013 => 'https://www.accuweather.com/en/fr/paris-13-gobelins/75013/daily-weather-forecast/179154_pc', 75015 => 'https://www.accuweather.com/en/fr/paris-15-vaugirard/75015/daily-weather-forecast/179156_pc', 75019 => 'https://www.accuweather.com/en/fr/paris-19-buttes-chaumont/75019/daily-weather-forecast/179160_pc', 75116 => 'https://www.accuweather.com/en/fr/paris-16-passy/75116/daily-weather-forecast/179246_pc' @@ -55,6 +77,23 @@ class WeatherCommand extends DoctrineCommand { ///Set curl handler private $ch = null; + ///Set manager registry + private $doctrine; + + ///Set filesystem + private $filesystem; + + ///Weather command constructor + public function __construct(ManagerRegistry $doctrine, Filesystem $filesystem) { + parent::__construct($doctrine); + + //Set entity manager + $this->doctrine = $doctrine; + + //Set filesystem + $this->filesystem = $filesystem; + } + ///Configure attribute command protected function configure() { //Configure the class @@ -70,12 +109,30 @@ class WeatherCommand extends DoctrineCommand { } ///Process the attribution - protected function execute(InputInterface $input, OutputInterface $output) { - //Fetch doctrine - $doctrine = $this->getDoctrine(); + protected function execute(InputInterface $input, OutputInterface $output): int { + //Kernel object + $kernel = $this->getApplication()->getKernel(); + + //Tmp directory + $tmpdir = $kernel->getContainer()->getParameter('kernel.project_dir').'/var/cache/weather'; + + //Set tmpdir + //XXX: worst case scenario we have 3 files per zipcode plus daily + if (!is_dir($tmpdir)) { + try { + //Create dir + $this->filesystem->mkdir($tmpdir, 0775); + } catch (IOException $exception) { + //Display error + echo 'Create dir '.$exception->getPath().' failed'."\n"; + + //Exit with failure + exit(self::FAILURE); + } + } - //Get manager - $manager = $doctrine->getManager(); + //Cleanup kernel + unset($kernel); //Tidy object $tidy = new \tidy(); @@ -89,7 +146,7 @@ class WeatherCommand extends DoctrineCommand { //Process hourly accuweather if (($command = $input->getFirstArgument()) == 'rapsysair:weather:hourly' || $command == 'rapsysair:weather') { //Fetch hourly sessions to attribute - $types['hourly'] = $doctrine->getRepository(Session::class)->findAllPendingHourlyWeather(); + $types['hourly'] = $this->doctrine->getRepository(Session::class)->findAllPendingHourlyWeather(); //Iterate on each session foreach($types['hourly'] as $sessionId => $session) { @@ -132,7 +189,7 @@ class WeatherCommand extends DoctrineCommand { //Process daily accuweather if ($command == 'rapsysair:weather:daily' || $command == 'rapsysair:weather') { //Fetch daily sessions to attribute - $types['daily'] = $doctrine->getRepository(Session::class)->findAllPendingDailyWeather(); + $types['daily'] = $this->doctrine->getRepository(Session::class)->findAllPendingDailyWeather(); //Iterate on each session foreach($types['daily'] as $sessionId => $session) { @@ -159,24 +216,6 @@ class WeatherCommand extends DoctrineCommand { } } - //Get filesystem - $filesystem = new Filesystem(); - - //Set tmpdir - //XXX: worst case scenario we have 3 files per zipcode - if (!is_dir($tmpdir = sys_get_temp_dir().'/accuweather')) { - try { - //Create dir - $filesystem->mkdir($tmpdir, 0775); - } catch (IOExceptionInterface $exception) { - //Display error - echo 'Create dir '.$exception->getPath().' failed'."\n"; - - //Exit with failure - exit(self::FAILURE); - } - } - //Init curl $this->curl_init(); @@ -219,20 +258,20 @@ class WeatherCommand extends DoctrineCommand { //Load simplexml //XXX: trash all xmlns= broken tags - $sx = new \SimpleXMLElement(str_replace(['xmlns=', 'xlink:href='], ['xns=', 'href='], $tidy)); + $sx = new \SimpleXMLElement(str_replace(['xmlns=', 'xlink:href='], ['xns=', 'href='], (string)$tidy)); //Process daily if ($day == 'daily') { //Iterate on each link containing data - foreach($sx->xpath('//a[@class="daily-forecast-card"]') as $node) { + foreach($sx->xpath('//a[contains(@class,"daily-forecast-card")]') as $node) { //Get date $dsm = trim($node->div[0]->h2[0]->span[1]); //Get temperature - $temperature = str_replace('°', '', $node->div[0]->div[0]->span[0]); + $temperature = str_replace('°', '', (string)$node->div[0]->div[0]->span[0]); //Get rainrisk - $rainrisk = str_replace('%', '', trim($node->div[2]))/100; + $rainrisk = trim(str_replace('%', '', (string)$node->div[1]))/100; //Store data $data[$zipcode][$dsm]['daily'] = [ @@ -247,28 +286,31 @@ class WeatherCommand extends DoctrineCommand { #/html/body/div[1]/div[5]/div[1]/div[1]/div[1]/div[1]/div[1]/div/h2/span[1] foreach($sx->xpath('//div[@data-shared="false"]') as $node) { //Get hour - $hour = trim($node->div[0]->div[0]->h2[0]->span[0]); + $hour = trim(str_replace(' h', '', (string)$node->div[0]->div[0]->div[0]->div[0]->div[0]->h2[0])); - //Get dsm - $dsm = trim($node->div[0]->div[0]->h2[0]->span[1]); + //Compute dsm from day (1=d,2=d+1,3=d+2) + $dsm = (new \DateTime('+'.($day - 1).' day'))->format('d/m'); //Get temperature - $temperature = str_replace('°', '', $node->div[0]->div[0]->div[0]); + $temperature = str_replace('°', '', (string)$node->div[0]->div[0]->div[0]->div[0]->div[1]); //Get realfeel - $realfeel = str_replace(['RealFeel® ', '°'], '', trim($node->div[0]->div[0]->span[0])); + $realfeel = trim(str_replace(['RealFeel®', '°'], '', (string)$node->div[0]->div[0]->div[0]->div[1]->div[0]->div[0]->div[0])); //Get rainrisk - $rainrisk = str_replace('%', '', trim($node->div[0]->div[0]->div[1]))/100; - - //Label is Rain when we have a rainfall - if (($pluviolabel = trim($node->div[1]->div[0]->div[0]->div[1]->p[1])) == 'Rain') { - //Get rainfall - $rainfall = str_replace(' mm', '', $node->div[1]->div[0]->div[0]->div[1]->p[1]->span[0]); - //Cloud Cover, no rainfall - } else { - //Set rainfall to 0 (mm) - $rainfall = 0; + $rainrisk = floatval(str_replace('%', '', trim((string)$node->div[0]->div[0]->div[0]->div[2]->div[0]))/100); + + //Set rainfall to 0 (mm) + $rainfall = 0; + + //Iterate on each entry + //TODO: wind and other infos are present in $node->div[1]->div[0]->div[1]->div[0]->p + foreach($node->div[1]->div[0]->div[1]->div[0]->p as $p) { + //Lookup for rain entry if present + if (in_array(trim((string)$p), ['Rain', 'Pluie'])) { + //Get rainfall + $rainfall = floatval(str_replace(' mm', '', (string)$p->span[0])); + } } //Store data @@ -337,11 +379,11 @@ class WeatherCommand extends DoctrineCommand { $hour = $type=='daily'?$type:$time->format('H'); //Check data availability - //XXX: should never happen - #if (!isset($data[$zipcode][$dsm][$hour])) { - # //Skip unavailable data - # continue; - #} + //XXX: sometimes startup delay causes weather data to be unavailable for session first hour + if (!isset($data[$zipcode][$dsm][$hour])) { + //Skip unavailable data + continue; + } //Set info alias $info = $data[$zipcode][$dsm][$hour]; @@ -411,7 +453,6 @@ class WeatherCommand extends DoctrineCommand { //Check if realfeel differ if ($session->getRealfeel() !== $realfeel) { //Set average realfeel - #$meteo['realfeel'] = array_sum($meteo['realfeel'])/count($meteo['realfeel']); $session->setRealfeel($realfeel); } @@ -436,7 +477,6 @@ class WeatherCommand extends DoctrineCommand { //Check if temperature differ if ($session->getTemperature() !== $temperature) { //Set average temperature - #$meteo['temperature'] = array_sum($meteo['temperature'])/count($meteo['temperature']); $session->setTemperature($temperature); } @@ -456,7 +496,7 @@ class WeatherCommand extends DoctrineCommand { } //Flush to get the ids - $manager->flush(); + $this->doctrine->getManager()->flush(); //Close curl handler $this->curl_close();