eveseat/eveapi

View on GitHub
src/Jobs/PlanetaryInteraction/Character/PlanetDetail.php

Summary

Maintainability
C
1 day
Test Coverage
<?php

/*
 * This file is part of SeAT
 *
 * Copyright (C) 2015 to present Leon Jacobs
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

namespace Seat\Eveapi\Jobs\PlanetaryInteraction\Character;

use Seat\Eveapi\Jobs\AbstractAuthCharacterJob;
use Seat\Eveapi\Models\PlanetaryInteraction\CharacterPlanetContent;
use Seat\Eveapi\Models\PlanetaryInteraction\CharacterPlanetExtractor;
use Seat\Eveapi\Models\PlanetaryInteraction\CharacterPlanetFactory;
use Seat\Eveapi\Models\PlanetaryInteraction\CharacterPlanetHead;
use Seat\Eveapi\Models\PlanetaryInteraction\CharacterPlanetLink;
use Seat\Eveapi\Models\PlanetaryInteraction\CharacterPlanetPin;
use Seat\Eveapi\Models\PlanetaryInteraction\CharacterPlanetRoute;
use Seat\Eveapi\Models\PlanetaryInteraction\CharacterPlanetRouteWaypoint;
use Seat\Eveapi\Models\RefreshToken;

/**
 * Class PlanetDetail.
 *
 * @package Seat\Eveapi\Jobs\PlanetaryInteraction\Character
 */
class PlanetDetail extends AbstractAuthCharacterJob
{

    /**
     * @var string
     */
    protected $method = 'get';

    /**
     * @var string
     */
    protected $endpoint = '/characters/{character_id}/planets/{planet_id}/';

    /**
     * @var string
     */
    protected $version = 'v3';

    /**
     * @var string
     */
    protected $scope = 'esi-planets.manage_planets.v1';

    /**
     * @var array
     */
    protected $tags = ['character', 'pi'];

    /**
     * @var int
     */
    private $planet_id;

    /**
     * @var \Illuminate\Support\Collection
     */
    private $planet_pins;

    /**
     * @var \Illuminate\Support\Collection
     */
    private $planet_factories;

    /**
     * @var \Illuminate\Support\Collection
     */
    private $planet_extractors;

    /**
     * @var \Illuminate\Support\Collection
     */
    private $planet_heads;

    /**
     * @var \Illuminate\Support\Collection
     */
    private $planet_links;

    /**
     * @var \Illuminate\Support\Collection
     */
    private $planet_waypoints;

    /**
     * @var \Illuminate\Support\Collection
     */
    private $planet_routes;

    /**
     * @var \Illuminate\Support\Collection
     */
    private $planet_contents;

    /**
     * PlanetDetail constructor.
     *
     * @param  RefreshToken  $token
     * @param  int  $planet_id
     */
    public function __construct(RefreshToken $token, int $planet_id)
    {
        $this->planet_id = $planet_id;

        $this->planet_pins = collect();
        $this->planet_factories = collect();
        $this->planet_extractors = collect();
        $this->planet_heads = collect();
        $this->planet_links = collect();
        $this->planet_waypoints = collect();
        $this->planet_routes = collect();
        $this->planet_contents = collect();

        parent::__construct($token);
    }

    /**
     * Execute the job.
     *
     * @throws \Throwable
     */
    public function handle()
    {
        $response = $this->retrieve([
            'character_id' => $this->getCharacterId(),
            'planet_id' => $this->planet_id,
        ]);

        $planet = $response->getBody();

        // seed database with pins
        collect($planet->pins)->each(function ($pin) {

            CharacterPlanetPin::firstOrNew([
                'character_id' => $this->getCharacterId(),
                'planet_id' => $this->planet_id,
                'pin_id' => $pin->pin_id,
            ])->fill([
                'type_id' => $pin->type_id,
                'schematic_id' => $pin->schematic_id ?? null,
                'latitude' => $pin->latitude,
                'longitude' => $pin->longitude,
                'install_time' => property_exists($pin, 'install_time') ?
                    carbon($pin->install_time) : null,
                'expiry_time' => property_exists($pin, 'expiry_time') ?
                    carbon($pin->expiry_time) : null,
                'last_cycle_start' => property_exists($pin, 'last_cycle_start') ?
                    carbon($pin->last_cycle_start) : null,
            ])->save();

            // Collect data for the cleanup phase
            $this->planet_pins->push($pin->pin_id);

            if (property_exists($pin, 'factory_details')) {

                CharacterPlanetFactory::firstOrNew([
                    'character_id' => $this->getCharacterId(),
                    'planet_id' => $this->planet_id,
                    'pin_id' => $pin->pin_id,
                ])->fill([
                    'schematic_id' => $pin->factory_details->schematic_id,
                ])->save();

                // seeding garbage collector
                $this->planet_factories->push($pin->pin_id);
            }

            if (property_exists($pin, 'extractor_details')) {

                CharacterPlanetExtractor::firstOrNew([
                    'character_id' => $this->getCharacterId(),
                    'planet_id' => $this->planet_id,
                    'pin_id' => $pin->pin_id,
                ])->fill([
                    'product_type_id' => $pin->extractor_details->product_type_id ?? null,
                    'cycle_time' => $pin->extractor_details->cycle_time ?? null,
                    'head_radius' => $pin->extractor_details->head_radius ?? null,
                    'qty_per_cycle' => $pin->extractor_details->qty_per_cycle ?? null,
                ])->save();

                // Collect data for the cleanup phase
                $this->planet_extractors->push($pin->pin_id);

                collect($pin->extractor_details->heads)->each(function ($head) use ($pin) {

                    CharacterPlanetHead::firstOrNew([
                        'character_id' => $this->getCharacterId(),
                        'planet_id' => $this->planet_id,
                        'extractor_id' => $pin->pin_id,
                        'head_id' => $head->head_id,
                    ])->fill([
                        'latitude' => $head->latitude,
                        'longitude' => $head->longitude,
                    ])->save();

                    // seeding garbage collector
                    $this->planet_heads->push([
                        'extractor_id' => $pin->pin_id,
                        'head_id' => $head->head_id,
                    ]);
                });
            }

            if (property_exists($pin, 'contents')) {

                collect($pin->contents)->each(function ($content) use ($pin) {

                    CharacterPlanetContent::firstOrNew([
                        'character_id' => $this->getCharacterId(),
                        'planet_id' => $this->planet_id,
                        'pin_id' => $pin->pin_id,
                        'type_id' => $content->type_id,
                    ])->fill([
                        'amount' => $content->amount,
                    ])->save();

                    // seeding garbage collector
                    $this->planet_contents->push([
                        'pin_id' => $pin->pin_id,
                        'type_id' => $content->type_id,
                    ]);

                });
            }
        });

        collect($planet->links)->each(function ($link) {

            CharacterPlanetLink::firstOrNew([
                'character_id' => $this->getCharacterId(),
                'planet_id' => $this->planet_id,
                'source_pin_id' => $link->source_pin_id,
                'destination_pin_id' => $link->destination_pin_id,
            ])->fill([
                'link_level' => $link->link_level,
            ])->save();

            // Collect data for the cleanup phase
            $this->planet_links->push([
                'source_pin_id' => $link->source_pin_id,
                'destination_pin_id' => $link->destination_pin_id,
            ]);

        });

        collect($planet->routes)->each(function ($route) {

            CharacterPlanetRoute::firstOrNew([
                'character_id' => $this->getCharacterId(),
                'planet_id' => $this->planet_id,
                'route_id' => $route->route_id,
            ])->fill([
                'source_pin_id' => $route->source_pin_id,
                'destination_pin_id' => $route->destination_pin_id,
                'content_type_id' => $route->content_type_id,
                'quantity' => $route->quantity,
            ])->save();

            // seeding garbage collector
            $this->planet_routes->push($route->route_id);

            if (property_exists($route, 'waypoints')) {
                collect($route->waypoints)->each(function ($waypoint) use ($route) {

                    CharacterPlanetRouteWaypoint::firstOrNew([
                        'character_id' => $this->getCharacterId(),
                        'planet_id' => $this->planet_id,
                        'route_id' => $route->route_id,
                        'pin_id' => $waypoint,
                    ])->save();

                    // seeding garbage collector
                    $this->planet_waypoints->push([
                        'route_id' => $route->route_id,
                        'pin_id' => $waypoint,
                    ]);

                });
            }
        });

        $this->planetCleanup();
    }

    /**
     * Performs a cleanup of any routes, links or contents
     * of a planet.
     *
     * @throws \Exception
     */
    private function planetCleanup()
    {

        // cleaning all waypoints
        $this->cleanRouteWaypoints();

        // cleaning all routes
        $this->cleanRoutes();

        // cleaning links
        $this->cleanLinks();

        // cleaning contents
        $this->cleanContents();

        // cleaning heads
        $this->cleanHeads();

        // cleaning extractors
        $this->cleanExtractors();

        // cleaning factories
        $this->cleanFactories();

        // cleaning pins
        $this->cleanPins();
    }

    /**
     * @param  $planet
     *
     * @throws \Exception
     */
    private function cleanRouteWaypoints()
    {
        // retrieve all waypoints which have not been returned by API.
        // We will run a delete statement on those selected rows in order to avoid any deadlock.
        $this->planet_waypoints->groupBy('route_id')->each(function ($pins) {
            $route = $pins->first();

            CharacterPlanetRouteWaypoint::where('character_id', $this->getCharacterId())
                ->where('planet_id', $this->planet_id)
                ->where('route_id', $route['route_id'])
                ->whereNotIn('pin_id', $pins->pluck('pin_id'))
                ->delete();
        });
    }

    /**
     * @throws \Exception
     */
    private function cleanRoutes()
    {
        // retrieve all routes which have not been returned by API.
        // We will run a delete statement on those selected rows in order to avoid any deadlock.
        $existing_routes = CharacterPlanetRoute::where('character_id', $this->getCharacterId())
            ->where('planet_id', $this->planet_id)
            ->whereNotIn('route_id', $this->planet_routes->toArray())
            ->get();

        CharacterPlanetRoute::where('character_id', $this->getCharacterId())
            ->where('planet_id', $this->planet_id)
            ->whereIn('route_id', $existing_routes->pluck('route_id')->toArray())
            ->delete();
    }

    /**
     * @throws \Exception
     */
    private function cleanLinks()
    {
        // retrieve all links which have not been returned by API.
        // We will run a delete statement on those selected rows in order to avoid any deadlock.
        $this->planet_links->groupBy('source_pin_id')->each(function ($links) {
            $from = $links->first();

            CharacterPlanetLink::where('character_id', $this->getCharacterId())
                ->where('planet_id', $this->planet_id)
                ->where('source_pin_id', $from['source_pin_id'])
                ->whereNotIn('destination_pin_id', $links->pluck('destination_pin_id'))
                ->delete();
        });
    }

    /**
     * @throws \Exception
     */
    private function cleanContents()
    {
        // retrieve all contents which have not been returned by API.
        // We will run a delete statement on those selected rows in order to avoid any deadlock.
        $this->planet_contents->groupBy('type_id')->each(function ($pins) {
            $type = $pins->first();

            CharacterPlanetContent::where('character_id', $this->getCharacterId())
                ->where('type_id', $type['type_id'])
                ->whereNotIn('pin_id', $pins->pluck('pin_id'))
                ->delete();
        });
    }

    /**
     * @throws \Exception
     */
    private function cleanHeads()
    {
        // retrieve all heads which have not been returned by API.
        // We will run a delete statement on those selected rows in order to avoid any deadlock.
        $this->planet_heads->groupBy('extractor_id')->each(function ($heads) {
            $extractor = $heads->first();

            CharacterPlanetHead::where('character_id', $this->getCharacterId())
                ->where('extractor_id', $extractor['extractor_id'])
                ->whereNotIn('head_id', $heads->pluck('head_id'))
                ->delete();
        });
    }

    /**
     * @throws \Exception
     */
    private function cleanExtractors()
    {
        // retrieve all extractors which have not been returned by API.
        // We will run a delete statement on those selected rows in order to avoid any deadlock.
        $existing_extractors = CharacterPlanetExtractor::where('character_id', $this->getCharacterId())
            ->where('planet_id', $this->planet_id)
            ->whereNotIn('pin_id', $this->planet_extractors->toArray())
            ->get();

        CharacterPlanetExtractor::where('character_id', $this->getCharacterId())
            ->where('planet_id', $this->planet_id)
            ->whereIn('pin_id', $existing_extractors->pluck('pin_id')->toArray())
            ->delete();
    }

    /**
     * @throws \Exception
     */
    private function cleanFactories()
    {
        // retrieve all factories which have not been returned by API.
        // We will run a delete statement on those selected rows in order to avoid any deadlock.
        $existing_factories = CharacterPlanetFactory::where('character_id', $this->getCharacterId())
            ->where('planet_id', $this->planet_id)
            ->whereNotIn('pin_id', $this->planet_factories->toArray())
            ->get();

        CharacterPlanetFactory::where('character_id', $this->getCharacterId())
            ->where('planet_id', $this->planet_id)
            ->whereIn('pin_id', $existing_factories->pluck('pin_id')->toArray())
            ->delete();
    }

    /**
     * @throws \Exception
     */
    private function cleanPins()
    {
        // retrieve all pins which have not been returned by API.
        // We will run a delete statement on those selected rows in order to avoid any deadlock.
        $existing_pins = CharacterPlanetPin::where('character_id', $this->getCharacterId())
            ->where('planet_id', $this->planet_id)
            ->whereNotIn('pin_id', $this->planet_pins->toArray())
            ->get();

        CharacterPlanetPin::where('character_id', $this->getCharacterId())
            ->where('planet_id', $this->planet_id)
            ->whereIn('pin_id', $existing_pins->pluck('pin_id')->toArray())
            ->delete();
    }
}