Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
composer.phar
composer.lock
/composer.lock
/vendor/

.idea
Expand Down
49 changes: 39 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,24 @@ This library allows to easily detect the PHP stack (Wordpress, Laravel, Symfony

Supported Stacks for now:

- Wordpress
- Bolt CMS
- Cakephp
- Codeigniter
- Craft CMS
- Drupal
- Grav CMS
- Laravel
- Symfony
- Leaf PHP
- Lunar
- October CMS
- Shopware
- Statamic
- Craft CMS
- Symfony
- Tempest
- Twill
- Typo3 CMS
- Winter CMS
- Wordpress

## Install

Expand All @@ -32,7 +45,17 @@ use Einenlum\PhpStackDetector\StackType;

$factory = new FilesystemDetectorFactory();
$detector = $factory->create();
$stack = $detector->getStack('/path/to/a/symfony/directory');
$config = $detector->getFullConfiguration('/path/to/a/symfony/directory');

$phpConfiguration = $config->phpConfiguration;

// value from config platform php
$phpConfiguration->phpVersion->version; // 8.3
// value from require php
$phpConfiguration->phpVersion->requirements; // ^7.2|^8.0
$phpConfiguration->requiredExtensions; // ['intl', 'curl']

$stack = $config->stack;

$stack->type === StackType::SYMFONY;
$stack->version; // 5.4
Expand All @@ -49,7 +72,16 @@ $stack; // null
$factory = new GithubDetectorFactory();
$detector = $factory->create();

$stack = $detector->getStack('symfony/demo');
$config = $detector->getFullConfiguration('/path/to/a/symfony/directory');

$phpConfiguration = $config->phpConfiguration;
// value from config platform php
$phpConfiguration->phpVersion->version; // 8.3
// value from require php
$phpConfiguration->phpVersion->requirements; // ^7.2|^8.0
$phpConfiguration->requiredExtensions; // ['intl', 'curl']

$stack = $config->stack;

$stack->type === StackType::SYMFONY;
$stack->version; // 6.3.0
Expand All @@ -59,13 +91,10 @@ $client = new \Github\Client();
$client->authenticate('some_access_token', null, \Github\AuthMethod::ACCESS_TOKEN);
$detector = $factory->create($client);

$stack = $detector->getStack('einenlum/private-repo');
$config = $detector->getFullConfiguration('einenlum/private-repo');

// optionally: detect the stack on a specific branch
$stack = $detector->getStack('einenlum/private-repo:branch-name');

$stack->type === StackType::SYMFONY;
$stack->version; // 6.3.0
$config = $detector->getFullConfiguration('einenlum/private-repo:branch-name');
```

You can also use the CLI to test it.
Expand Down
22 changes: 14 additions & 8 deletions bin/detect-github.php
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
<?php

require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__.'/../vendor/autoload.php';

use Einenlum\PhpStackDetector\Detector;
use Einenlum\PhpStackDetector\Factory\GithubDetectorFactory;
use Github\AuthMethod;

$factory = new GithubDetectorFactory();

$accessToken = getenv('GITHUB_ACCESS_TOKEN');
if ($accessToken) {
$client = new \Github\Client();
$client = new Github\Client();
$client->authenticate($accessToken, null, AuthMethod::ACCESS_TOKEN);
$detector = $factory->create($client);
} else {
Expand All @@ -19,18 +18,25 @@

$directory = $argv[1] ?? null;
if (null === $directory) {
echo 'Please provide a directory to scan' . "\n";
echo 'Please provide a directory to scan'."\n";
exit(1);
}

$subDirectory = $argv[2] ?? null;

$stack = $detector->getStack($directory, $subDirectory);
$config = $detector->getFullConfiguration($directory, $subDirectory);

$phpConfig = $config->phpConfiguration;
echo 'Detected PHP version: '.($phpConfig->phpVersion?->version ?: 'Unknown version')."\n";
echo 'Detected PHP requirements: '.($phpConfig->phpVersion?->requirements ?: 'Unknown version')."\n";
echo 'Required extensions: '.(empty($phpConfig->requiredExtensions) ? 'None' : implode(', ', $phpConfig->requiredExtensions))."\n";

$stack = $config->stack;

if (null === $stack) {
echo 'No stack detected' . "\n";
echo 'No stack detected'."\n";
exit(0);
}

echo 'Detected stack: ' . $stack->type->value . "\n";
echo 'Version: ' . ($stack->version ?: 'Unknown version') . "\n";
echo 'Detected stack: '.$stack->type->value."\n";
echo 'Version: '.($stack->version ?: 'Unknown version')."\n";
19 changes: 13 additions & 6 deletions bin/detect-local.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__.'/../vendor/autoload.php';

use Einenlum\PhpStackDetector\Factory\FilesystemDetectorFactory;

Expand All @@ -9,18 +9,25 @@

$directory = $argv[1] ?? null;
if (null === $directory) {
echo 'Please provide a directory to scan' . "\n";
echo 'Please provide a directory to scan'."\n";
exit(1);
}

$subDirectory = $argv[2] ?? null;

$stack = $detector->getStack($directory, $subDirectory);
$config = $detector->getFullConfiguration($directory, $subDirectory);

$phpConfig = $config->phpConfiguration;
echo 'Detected PHP version: '.($phpConfig->phpVersion?->version ?: 'Unknown version')."\n";
echo 'Detected PHP requirements: '.($phpConfig->phpVersion?->requirements ?: 'Unknown version')."\n";
echo 'Required extensions: '.(empty($phpConfig->requiredExtensions) ? 'None' : implode(', ', $phpConfig->requiredExtensions))."\n";

$stack = $config->stack;

if (null === $stack) {
echo 'No stack detected' . "\n";
echo 'No stack detected'."\n";
exit(0);
}

echo 'Detected stack: ' . $stack->type->value . "\n";
echo 'Version: ' . ($stack->version ?: 'Unknown version') . "\n";
echo 'Detected stack: '.$stack->type->value."\n";
echo 'Version: '.($stack->version ?: 'Unknown version')."\n";
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"nyholm/psr7": "^1.8"
},
"scripts": {
"unit-test": "phpunit tests",
"unit-test": "phpunit tests --display-warnings",
"static-analysis": "phpstan",
"test-cs": "./vendor/bin/php-cs-fixer fix --dry-run --diff -v",
"fix-cs": "./vendor/bin/php-cs-fixer fix --diff -v",
Expand Down
76 changes: 36 additions & 40 deletions lib/Composer/ComposerConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
use Einenlum\PhpStackDetector\Exception\CacheMissException;
use Einenlum\PhpStackDetector\Exception\ResourceNotFoundException;

/**
* We use an array cache so that we don't make expensive calls to the adapter
* each time. This provider is used in multiple places during a single run.
*/
class ComposerConfigProvider
{
/** @var array<string, ComposerConfig|null> */
Expand All @@ -18,56 +22,41 @@ public function __construct(
) {
}

/**
* This returns the content of the composer lock file if it exists,
* otherwise the composer json file if it exists, otherwise null.
*/
public function getComposerConfig(
ComposerConfigType $type,
string $baseUri,
?string $subDirectory,
): ?ComposerConfig {
try {
return $this->getFromCache($baseUri, $subDirectory);
return $this->getFromCache($type, $baseUri, $subDirectory);
} catch (CacheMissException) {
}

$lockContent = $this->getConfig(
$content = $this->getFileContent(
$type,
$baseUri,
$subDirectory,
'composer.lock'
);

if (null !== $lockContent) {
$config = new ComposerConfig(
ComposerConfigType::LOCK,
$lockContent
);
$this->setToCache($baseUri, $subDirectory, $config);

return $config;
}

$jsonContent = $this->getConfig(
$baseUri,
$subDirectory,
'composer.json'
);

if (null !== $jsonContent) {
$config = new ComposerConfig(
ComposerConfigType::JSON,
$jsonContent
);

$this->setToCache($baseUri, $subDirectory, $config);

return $config;
}
$config = $content ? new ComposerConfig($type, $content) : null;

$this->setToCache($baseUri, $subDirectory, null);
$this->setToCache($type, $baseUri, $subDirectory, $config);

return null;
return $config;
}

/** @return array<string, mixed>|null */
private function getConfig(string $baseUri, ?string $subDirectory, string $filename): ?array
{
private function getFileContent(
ComposerConfigType $type,
string $baseUri,
?string $subDirectory,
): ?array {
$filename = ComposerConfigType::LOCK === $type ? 'composer.lock' : 'composer.json';

if (!$this->adapter->directoryExists($baseUri, $subDirectory)) {
return null;
}
Expand All @@ -91,21 +80,25 @@ private function getConfig(string $baseUri, ?string $subDirectory, string $filen
}

private function setToCache(
ComposerConfigType $type,
string $baseUri,
?string $subDirectory,
?ComposerConfig $config,
): void {
$cacheKey = $this->getCacheKey($baseUri, $subDirectory);
$cacheKey = $this->getCacheKey($type, $baseUri, $subDirectory);

$this->cache[$cacheKey] = $config;
}

/**
* @throws CacheMissException
*/
private function getFromCache(string $baseUri, ?string $subDirectory): ?ComposerConfig
{
$cacheKey = $this->getCacheKey($baseUri, $subDirectory);
private function getFromCache(
ComposerConfigType $type,
string $baseUri,
?string $subDirectory,
): ?ComposerConfig {
$cacheKey = $this->getCacheKey($type, $baseUri, $subDirectory);

if (!array_key_exists($cacheKey, $this->cache)) {
throw new CacheMissException();
Expand All @@ -114,8 +107,11 @@ private function getFromCache(string $baseUri, ?string $subDirectory): ?Composer
return $this->cache[$cacheKey];
}

private function getCacheKey(string $baseUri, ?string $subDirectory): string
{
return $baseUri.$subDirectory;
private function getCacheKey(
ComposerConfigType $type,
string $baseUri,
?string $subDirectory,
): string {
return $baseUri.$subDirectory.':'.$type->value;
}
}
6 changes: 3 additions & 3 deletions lib/Composer/ComposerConfigType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Einenlum\PhpStackDetector\Composer;

enum ComposerConfigType
enum ComposerConfigType: string
{
case JSON;
case LOCK;
case JSON = 'json';
case LOCK = 'lock';
}
23 changes: 17 additions & 6 deletions lib/Composer/PackageVersionProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ public function getVersionForPackage(
?string $subDirectory,
array $packageNames,
): ?PackageVersion {
$config = $this->configProvider->getComposerConfig($baseUri, $subDirectory);
if (null === $config) {
return null;
}
$lock = $this->configProvider->getComposerConfig(
ComposerConfigType::LOCK,
$baseUri,
$subDirectory
);

if (ComposerConfigType::LOCK === $config->type) {
if ($lock) {
foreach ($packageNames as $packageName) {
foreach ($config->content['packages'] as $package) {
foreach ($lock->content['packages'] as $package) {
if ($package['name'] === $packageName) {
return new PackageVersion(
null,
Expand All @@ -38,6 +39,16 @@ public function getVersionForPackage(
return null;
}

$config = $this->configProvider->getComposerConfig(
ComposerConfigType::JSON,
$baseUri,
$subDirectory
);

if (null === $config || !isset($config->content['require'])) {
return null;
}

foreach ($packageNames as $name) {
foreach ($config->content['require'] as $packageName => $requirement) {
if ($packageName === $name) {
Expand Down
Loading
Loading