Skip to content

Commit 2084c9e

Browse files
committed
Include helper AuxDataPath.php
1 parent 182cc22 commit 2084c9e

File tree

2 files changed

+103
-2
lines changed

2 files changed

+103
-2
lines changed

composer.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,16 @@
22
"name": "araga/aux-data",
33
"description": "Lightweight, PSR-16 compliant key/value storage on top of SQLite using PDO. Perfect for CLI tools, configuration storage, and simple caching.",
44
"type": "library",
5-
"keywords": ["sqlite", "cache", "key-value", "storage", "pdo", "configuration", "psr-16", "simple-cache"],
5+
"keywords": [
6+
"sqlite",
7+
"cache",
8+
"key-value",
9+
"storage",
10+
"pdo",
11+
"configuration",
12+
"psr-16",
13+
"simple-cache"
14+
],
615
"license": "MIT",
716
"require": {
817
"php": ">=8.1",
@@ -25,4 +34,4 @@
2534
"support": {
2635
"issues": "https://github.com/araga/aux-data/issues"
2736
}
28-
}
37+
}

src/AuxDataPath.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Araga;
6+
7+
/**
8+
* Class AuxDataPath
9+
*
10+
* Helpers to determine sensible default paths when AuxData is installed
11+
* via Composer under the vendor/ directory.
12+
*
13+
* Typical Composer layout:
14+
*
15+
* project-root/
16+
* composer.json
17+
* vendor/
18+
* araga/
19+
* aux-data/
20+
* src/
21+
* AuxData.php
22+
* AuxDataPath.php
23+
*
24+
* This class tries to:
25+
* - Locate the project root by walking up until it finds composer.json
26+
* - Provide a convenient storage directory under that root
27+
*/
28+
final class AuxDataPath
29+
{
30+
/**
31+
* Maximum directory levels to traverse upwards when looking
32+
* for composer.json.
33+
*/
34+
private const MAX_ASCEND_LEVELS = 8;
35+
36+
/**
37+
* Try to detect the project root directory.
38+
*
39+
* Strategy:
40+
* - Start from this file's directory (__DIR__)
41+
* - Walk up until we find "composer.json"
42+
* - Stop after MAX_ASCEND_LEVELS to avoid infinite loops
43+
* - If nothing is found, fall back to assuming a standard
44+
* vendor/araga/aux-data/src layout and go 4 levels up.
45+
*
46+
* @return string Absolute path to the detected project root.
47+
*/
48+
public static function projectRoot(): string
49+
{
50+
$dir = __DIR__;
51+
$previous = null;
52+
$levels = 0;
53+
54+
while ($dir !== $previous && $levels < self::MAX_ASCEND_LEVELS) {
55+
if (file_exists($dir . DIRECTORY_SEPARATOR . 'composer.json')) {
56+
return $dir;
57+
}
58+
59+
$previous = $dir;
60+
$dir = \dirname($dir);
61+
$levels++;
62+
}
63+
64+
// Fallback: assume "vendor/araga/aux-data/src" structure
65+
// __DIR__ => .../vendor/araga/aux-data/src
66+
// dirname(__DIR__, 4) => .../project-root
67+
return \dirname(__DIR__, 4);
68+
}
69+
70+
/**
71+
* Return a storage directory under the detected project root.
72+
*
73+
* Example (default):
74+
* {projectRoot}/storage
75+
*
76+
* Example (custom):
77+
* AuxDataPath::storageDir('var/aux-data')
78+
* => {projectRoot}/var/aux-data
79+
*
80+
* This method does NOT create the directory, it only computes the path.
81+
*
82+
* @param string $relative Relative directory from the project root.
83+
*
84+
* @return string Absolute path to the storage directory.
85+
*/
86+
public static function storageDir(string $relative = 'storage'): string
87+
{
88+
return self::projectRoot()
89+
. DIRECTORY_SEPARATOR
90+
. str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $relative);
91+
}
92+
}

0 commit comments

Comments
 (0)