partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

SystemService.php (10182B)


      1 <?php
      2 
      3 namespace PartKeepr\CoreBundle\Services;
      4 
      5 use Doctrine\Bundle\DoctrineBundle\Registry;
      6 use Doctrine\DBAL\Version as DBALVersion;
      7 use Doctrine\ORM\EntityManager;
      8 use Doctrine\ORM\Tools\SchemaTool;
      9 use Doctrine\ORM\Version as ORMVersion;
     10 use Guzzle\Http\Client;
     11 use PartKeepr\CoreBundle\System\OperatingSystem;
     12 use PartKeepr\CoreBundle\System\SystemInformationRecord;
     13 use PartKeepr\CronLoggerBundle\Services\CronLoggerService;
     14 use Symfony\Component\DependencyInjection\ContainerAware;
     15 use Symfony\Component\DependencyInjection\ContainerInterface;
     16 
     17 class SystemService extends ContainerAware
     18 {
     19     /**
     20      * @var EntityManager
     21      */
     22     private $entityManager;
     23 
     24     /**
     25      * @var VersionService
     26      */
     27     private $versionService;
     28 
     29     /**
     30      * @var CronLoggerService
     31      */
     32     private $cronLoggerService;
     33 
     34     public function __construct(
     35         Registry $doctrine,
     36         ContainerInterface $container,
     37         VersionService $versionService,
     38         CronLoggerService $cronLoggerService
     39     ) {
     40         $this->entityManager = $doctrine->getManager();
     41         $this->setContainer($container);
     42         $this->versionService = $versionService;
     43         $this->cronLoggerService = $cronLoggerService;
     44     }
     45 
     46     /**
     47      * Returns a list of system information records.
     48      *
     49      * Please note that it is not defined which information is returned; the result
     50      * should be seen as "informational" to the system operator, not for automated purposes.
     51      *
     52      * @return SystemInformationRecord[] An array of SystemInformationRecords
     53      */
     54     public function getSystemInformation()
     55     {
     56         $aData = [];
     57 
     58         $aData[] = new SystemInformationRecord('Doctrine ORM', ORMVersion::VERSION, 'Libraries');
     59         $aData[] = new SystemInformationRecord('Doctrine DBAL', DBALVersion::VERSION, 'Libraries');
     60 
     61         $aData[] = new SystemInformationRecord('PHP Version', phpversion(), 'System');
     62 
     63         $os = new OperatingSystem();
     64 
     65         $aData[] = new SystemInformationRecord('Operating System Type', $os->getPlatform(), 'System');
     66         $aData[] = new SystemInformationRecord('Operating System Release', $os->getRelease(), 'System');
     67 
     68         $aData[] = new SystemInformationRecord('memory_limit', ini_get('memory_limit'), 'PHP');
     69         $aData[] = new SystemInformationRecord('post_max_size', ini_get('post_max_size'), 'PHP');
     70         $aData[] = new SystemInformationRecord('upload_max_filesize', ini_get('upload_max_filesize'), 'PHP');
     71         $aData[] = new SystemInformationRecord('allow_url_fopen', ini_get('allow_url_fopen'), 'PHP');
     72         $aData[] = new SystemInformationRecord('max_execution_time', ini_get('max_execution_time'), 'PHP');
     73 
     74         $queryCache = get_class($this->entityManager->getConfiguration()->getQueryCacheImpl());
     75         $metadataCache = get_class($this->entityManager->getConfiguration()->getMetadataCacheImpl());
     76 
     77         $aData[] = new SystemInformationRecord('Query Cache Implementation', $queryCache, 'PHP');
     78         $aData[] = new SystemInformationRecord('Metadata Cache Implementation', $metadataCache, 'PHP');
     79 
     80         $aData[] = new SystemInformationRecord(
     81             'Disk Space (Total)',
     82             $this->format_bytes($this->getTotalDiskSpace()),
     83             'PartKeepr'
     84         );
     85 
     86         $aData[] = new SystemInformationRecord(
     87             'Disk Space (Free)',
     88             $this->format_bytes($this->getFreeDiskSpace()),
     89             'PartKeepr'
     90         );
     91 
     92         $aData[] = new SystemInformationRecord(
     93             'Disk Space (Used)',
     94             $this->format_bytes($this->getUsedDiskSpace()),
     95             'PartKeepr'
     96         );
     97 
     98         $aData[] = new SystemInformationRecord(
     99             'Data Directory',
    100             realpath($this->container->getParameter('partkeepr.filesystem.data_directory')),
    101             'PartKeepr'
    102         );
    103 
    104         $aData[] = new SystemInformationRecord(
    105             'PartKeepr Version',
    106             $this->versionService->getCanonicalVersion(),
    107             'PartKeepr'
    108         );
    109 
    110         return $aData;
    111     }
    112 
    113     /**
    114      * Returns the database schema status.
    115      *
    116      * This method is usuall called once the user logs in, and alerts him if the schema is not up-to-date.
    117      *
    118      * Returns either status incomplete if the schema is not up-to-date, or complete if everything is OK.
    119      */
    120     public function getSystemStatus()
    121     {
    122         if ($this->container->getParameter('partkeepr.cronjob_check')) {
    123             $inactiveCronjobs = $this->cronLoggerService->getInactiveCronjobs(
    124                 $this->container->getParameter('partkeepr.required_cronjobs')
    125             );
    126         } else {
    127             // Skip cronjob tests
    128             $inactiveCronjobs = [];
    129         }
    130 
    131         return [
    132             'inactiveCronjobCount' => count($inactiveCronjobs),
    133             'inactiveCronjobs'     => $inactiveCronjobs,
    134             'schemaStatus'         => $this->getSchemaStatus(),
    135             'schemaQueries'        => $this->getSchemaQueries(),
    136         ];
    137     }
    138 
    139     /**
    140      * Checks if the schema is up-to-date. If yes, it returns "complete", if not, it returns "incomplete".
    141      *
    142      * @param none
    143      *
    144      * @return string Either "complete" or "incomplete"
    145      */
    146     protected function getSchemaStatus()
    147     {
    148         $queries = $this->getSchemaQueries();
    149 
    150         if (count($queries) > 0) {
    151             return 'incomplete';
    152         } else {
    153             return 'complete';
    154         }
    155     }
    156 
    157     /**
    158      * Returns all queries to be executed for a proper database update.
    159      *
    160      * @return array
    161      */
    162     protected function getSchemaQueries()
    163     {
    164         $metadatas = $this->entityManager->getMetadataFactory()->getAllMetadata();
    165 
    166         $schemaTool = new SchemaTool($this->entityManager);
    167 
    168         return $schemaTool->getUpdateSchemaSql($metadatas, true);
    169     }
    170 
    171     /**
    172      * Returns the available disk space for the configured data_dir.
    173      *
    174      * @return float
    175      */
    176     public function getFreeDiskSpace()
    177     {
    178         if ($this->container->getParameter('partkeepr.filesystem.quota') === false) {
    179             return disk_free_space($this->container->getParameter('partkeepr.filesystem.data_directory'));
    180         } else {
    181             return $this->getTotalDiskSpace() - $this->getUsedDiskSpace();
    182         }
    183     }
    184 
    185     public function getTotalDiskSpace()
    186     {
    187         if ($this->container->getParameter('partkeepr.filesystem.quota') === false) {
    188             return disk_total_space($this->container->getParameter('partkeepr.filesystem.data_directory'));
    189         } else {
    190             return $this->container->getParameter('partkeepr.filesystem.quota');
    191         }
    192     }
    193 
    194     /**
    195      * Returns the used disk space occupied by attachments etc.
    196      *
    197      * Does not count temporary files.
    198      *
    199      * @return int
    200      */
    201     public function getUsedDiskSpace()
    202     {
    203         if ($this->container->getParameter('partkeepr.filesystem.quota') === false) {
    204             return $this->getTotalDiskSpace() - $this->getFreeDiskSpace();
    205         }
    206 
    207         $fileEntities = [
    208             'PartKeepr\FootprintBundle\Entity\FootprintAttachment',
    209             'PartKeepr\FootprintBundle\Entity\FootprintImage',
    210             'PartKeepr\ManufacturerBundle\Entity\ManufacturerICLogo',
    211             'PartKeepr\PartBundle\Entity\PartAttachment',
    212             'PartKeepr\ProjectBundle\Entity\ProjectAttachment',
    213             'PartKeepr\StorageLocationBundle\Entity\StorageLocationImage',
    214         ];
    215 
    216         $size = 0;
    217         foreach ($fileEntities as $fileEntity) {
    218             $qb = $this->container->get('doctrine.orm.default_entity_manager')->createQueryBuilder();
    219             $qb->select('SUM(a.size)')->from($fileEntity, 'a');
    220 
    221             $size += $qb->getQuery()->getSingleScalarResult();
    222         }
    223 
    224         return $size;
    225     }
    226 
    227     /**
    228      * @param $number
    229      *
    230      * @return bool
    231      */
    232     protected function is_valid_value($number)
    233     {
    234         return is_numeric($number);
    235     }
    236 
    237     /**
    238      * Filter for converting bytes to a human-readable format, as Unix command "ls -h" does.
    239      *
    240      * @param string|int $number          A string or integer number value to format.
    241      * @param bool       $base2conversion Defines if the conversion has to be strictly performed as binary values or
    242      *                                    by using a decimal conversion such as 1 KByte = 1000 Bytes.
    243      *
    244      * @return string The number converted to human readable representation.
    245      */
    246     public function format_bytes($number, $base2conversion = true)
    247     {
    248         if (!$this->is_valid_value($number)) {
    249             return;
    250         }
    251         $unit = $base2conversion ? 1024 : 1000;
    252         if ($number < $unit) {
    253             return $number.' B';
    254         }
    255         $exp = intval((log($number) / log($unit)));
    256         $pre = ($base2conversion ? 'kMGTPE' : 'KMGTPE');
    257         $pre = $pre[$exp - 1].($base2conversion ? '' : 'i');
    258 
    259         return sprintf('%.1f %sB', $number / pow($unit, $exp), $pre);
    260     }
    261 
    262     /**
    263      * Returns the effective size from a human-readable byte format.
    264      *
    265      * Example:
    266      * getBytesFromHumanReadable("1M") will return 1048576.
    267      *
    268      * @param string $size_str The byte
    269      *
    270      * @return int The bytes
    271      */
    272     public function getBytesFromHumanReadable($size_str)
    273     {
    274         switch (substr($size_str, -1)) {
    275             case 'M':
    276             case 'm':
    277                 return (int) $size_str * 1048576;
    278             case 'K':
    279             case 'k':
    280                 return (int) $size_str * 1024;
    281             case 'G':
    282             case 'g':
    283                 return (int) $size_str * 1073741824;
    284             default:
    285                 return $size_str;
    286         }
    287     }
    288 
    289     public function getPatreonStatus()
    290     {
    291         $statusURI = $this->container->getParameter("partkeepr.patreon.statusuri");
    292 
    293         if ($statusURI === false) {
    294             return false;
    295         }
    296 
    297         try {
    298             $client = new Client();
    299             $request = $client->createRequest('GET', $statusURI, ['timeout' => 3.14]);
    300             $request->send();
    301 
    302             return json_decode($request->getResponse()->getBody(), true);
    303         } catch (\Exception $e) {
    304             return false;
    305         }
    306     }
    307 }