@artilingo/artiframe-cli 1.0.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +1 -1
  2. package/bin/artiframe.php +1 -1
  3. package/core-stubs/app/Database.php +1 -1
  4. package/core-stubs/app/DotEnv.php +1 -1
  5. package/core-stubs/app/R2Manager.php +1 -1
  6. package/core-stubs/bin/SystemMethod.php +292 -16
  7. package/core-stubs/bin/ViewMethod.php +146 -37
  8. package/core-stubs/docs/de.html +4419 -955
  9. package/core-stubs/docs/en.html +4419 -956
  10. package/core-stubs/docs/es.html +4419 -951
  11. package/core-stubs/docs/fr.html +4101 -536
  12. package/core-stubs/docs/tr.html +4978 -955
  13. package/core-stubs/stubs/service/image.stub +334 -0
  14. package/core-stubs/stubs/service/iyzico.stub +637 -0
  15. package/core-stubs/stubs/service/jwt.stub +312 -0
  16. package/core-stubs/stubs/service/pusher.stub +232 -0
  17. package/core-stubs/stubs/service/redis.stub +361 -0
  18. package/core-stubs/stubs/service/s3.stub +377 -0
  19. package/core-stubs/stubs/service/sentry.stub +139 -0
  20. package/core-stubs/stubs/service/stripe.stub +526 -0
  21. package/core-stubs/stubs/service/twilio.stub +361 -0
  22. package/package.json +4 -4
  23. package/src/App.php +69 -0
  24. package/src/Commands/AddCommand.php +392 -0
  25. package/src/Commands/GoCommand.php +48 -0
  26. package/src/Commands/ListCommand.php +67 -0
  27. package/src/Commands/NewProjectCommand.php +184 -30
  28. package/src/Commands/RemoveCommand.php +121 -0
  29. package/src/Commands/ServeCommand.php +71 -0
  30. package/src/Commands/ShowCommand.php +24 -0
  31. package/src/Lang/de.php +56 -0
  32. package/src/Lang/en.php +56 -0
  33. package/src/Lang/es.php +56 -0
  34. package/src/Lang/fr.php +56 -0
  35. package/src/Lang/tr.php +56 -0
@@ -0,0 +1,392 @@
1
+ <?php
2
+ namespace ArtiFrame\Cli\Commands;
3
+
4
+ use ArtiFrame\Cli\Services\Translator;
5
+
6
+ class AddCommand
7
+ {
8
+ private Translator $translator;
9
+
10
+ /**
11
+ * ArtiFrame'in desteklediği paket kayıt defteri.
12
+ *
13
+ * 'composer' => Composer paket adı
14
+ * 'type' => 'integrated' | 'direct'
15
+ * 'service' => Oluşturulacak sınıf dosyası yolu (integrated için)
16
+ * 'stub' => Stub dosya adı (integrated için)
17
+ * 'env' => .env dosyasına eklenecek satırlar (integrated için)
18
+ */
19
+ private array $registry = [
20
+ // ── Entegrasyonlu Paketler (Composer + Servis Sınıfı + .env) ───
21
+ 'iyzico' => [
22
+ 'composer' => 'iyzipay/iyzipay-php',
23
+ 'type' => 'integrated',
24
+ 'service' => 'src/Service/Iyzico.php',
25
+ 'stub' => 'iyzico.stub',
26
+ 'env' => [
27
+ '# ── iyzico ──────────────────────',
28
+ 'IYZICO_API_KEY=',
29
+ 'IYZICO_SECRET_KEY=',
30
+ 'IYZICO_BASE_URL=https://sandbox-api.iyzipay.com',
31
+ ],
32
+ ],
33
+ 'stripe' => [
34
+ 'composer' => 'stripe/stripe-php',
35
+ 'type' => 'integrated',
36
+ 'service' => 'src/Service/Stripe.php',
37
+ 'stub' => 'stripe.stub',
38
+ 'env' => [
39
+ '# ── stripe ──────────────────────',
40
+ 'STRIPE_SECRET_KEY=',
41
+ 'STRIPE_PUBLISHABLE_KEY=',
42
+ 'STRIPE_WEBHOOK_SECRET=',
43
+ ],
44
+ ],
45
+ 'jwt' => [
46
+ 'composer' => 'firebase/php-jwt',
47
+ 'type' => 'integrated',
48
+ 'service' => 'src/Auth/JwtAuth.php',
49
+ 'stub' => 'jwt.stub',
50
+ 'env' => [
51
+ '# ── jwt ─────────────────────────',
52
+ 'JWT_SECRET_KEY=',
53
+ 'JWT_ALGORITHM=HS256',
54
+ 'JWT_EXPIRY=3600',
55
+ ],
56
+ ],
57
+ 'image' => [
58
+ 'composer' => 'intervention/image',
59
+ 'type' => 'integrated',
60
+ 'service' => 'src/Service/ImageProcessor.php',
61
+ 'stub' => 'image.stub',
62
+ 'env' => [
63
+ '# ── image ───────────────────────',
64
+ 'IMAGE_DRIVER=gd',
65
+ 'IMAGE_QUALITY=80',
66
+ ],
67
+ ],
68
+ 's3' => [
69
+ 'composer' => 'aws/aws-sdk-php',
70
+ 'type' => 'integrated',
71
+ 'service' => 'src/Service/S3Storage.php',
72
+ 'stub' => 's3.stub',
73
+ 'env' => [
74
+ '# ── aws s3 ──────────────────────',
75
+ 'AWS_ACCESS_KEY_ID=',
76
+ 'AWS_SECRET_ACCESS_KEY=',
77
+ 'AWS_DEFAULT_REGION=eu-central-1',
78
+ 'AWS_BUCKET=',
79
+ 'AWS_ENDPOINT=',
80
+ ],
81
+ ],
82
+ 'sentry' => [
83
+ 'composer' => 'sentry/sentry',
84
+ 'type' => 'integrated',
85
+ 'service' => 'config/sentry.php',
86
+ 'stub' => 'sentry.stub',
87
+ 'env' => [
88
+ '# ── sentry ──────────────────────',
89
+ 'SENTRY_DSN=',
90
+ ],
91
+ ],
92
+ 'redis' => [
93
+ 'composer' => 'predis/predis',
94
+ 'type' => 'integrated',
95
+ 'service' => 'src/Service/RedisCache.php',
96
+ 'stub' => 'redis.stub',
97
+ 'env' => [
98
+ '# ── redis ───────────────────────',
99
+ 'REDIS_HOST=127.0.0.1',
100
+ 'REDIS_PORT=6379',
101
+ 'REDIS_PASSWORD=',
102
+ 'REDIS_DATABASE=0',
103
+ ],
104
+ ],
105
+ 'pusher' => [
106
+ 'composer' => 'pusher/pusher-php-server',
107
+ 'type' => 'integrated',
108
+ 'service' => 'src/Service/Pusher.php',
109
+ 'stub' => 'pusher.stub',
110
+ 'env' => [
111
+ '# ── pusher ──────────────────────',
112
+ 'PUSHER_APP_ID=',
113
+ 'PUSHER_APP_KEY=',
114
+ 'PUSHER_APP_SECRET=',
115
+ 'PUSHER_CLUSTER=eu',
116
+ ],
117
+ ],
118
+ 'twilio' => [
119
+ 'composer' => 'twilio/sdk',
120
+ 'type' => 'integrated',
121
+ 'service' => 'src/Service/Twilio.php',
122
+ 'stub' => 'twilio.stub',
123
+ 'env' => [
124
+ '# ── twilio ──────────────────────',
125
+ 'TWILIO_SID=',
126
+ 'TWILIO_AUTH_TOKEN=',
127
+ 'TWILIO_FROM_NUMBER=',
128
+ ],
129
+ ],
130
+
131
+ // ── Direkt Kullanılabilir Paketler (Sadece Composer) ───────────
132
+ 'phpmailer' => [
133
+ 'composer' => 'phpmailer/phpmailer',
134
+ 'type' => 'direct',
135
+ ],
136
+ 'mpdf' => [
137
+ 'composer' => 'mpdf/mpdf',
138
+ 'type' => 'direct',
139
+ ],
140
+ 'dompdf' => [
141
+ 'composer' => 'dompdf/dompdf',
142
+ 'type' => 'direct',
143
+ ],
144
+ 'spreadsheet' => [
145
+ 'composer' => 'phpoffice/phpspreadsheet',
146
+ 'type' => 'direct',
147
+ ],
148
+ 'qrcode' => [
149
+ 'composer' => 'endroid/qr-code',
150
+ 'type' => 'direct',
151
+ ],
152
+ 'guzzle' => [
153
+ 'composer' => 'guzzlehttp/guzzle',
154
+ 'type' => 'direct',
155
+ ],
156
+ 'uuid' => [
157
+ 'composer' => 'ramsey/uuid',
158
+ 'type' => 'direct',
159
+ ],
160
+ 'carbon' => [
161
+ 'composer' => 'nesbot/carbon',
162
+ 'type' => 'direct',
163
+ ],
164
+ 'monolog' => [
165
+ 'composer' => 'monolog/monolog',
166
+ 'type' => 'direct',
167
+ ],
168
+ ];
169
+
170
+ public function __construct(Translator $translator)
171
+ {
172
+ $this->translator = $translator;
173
+ }
174
+
175
+ public function execute(array $args): void
176
+ {
177
+ $packageAlias = strtolower($args[0] ?? '');
178
+
179
+ // ── Parametre kontrolü ───────────────────────────────────
180
+ if ($packageAlias === '') {
181
+ echo PHP_EOL;
182
+ echo " ❌ " . $this->translator->get('ADD_MISSING_NAME') . PHP_EOL;
183
+ echo PHP_EOL;
184
+ $this->showAvailablePackages();
185
+ return;
186
+ }
187
+
188
+ // ── "list" alt komutu ────────────────────────────────────
189
+ if ($packageAlias === 'list') {
190
+ $this->showAvailablePackages();
191
+ return;
192
+ }
193
+
194
+ // ── Kayıt defterinde ara ─────────────────────────────────
195
+ if (!isset($this->registry[$packageAlias])) {
196
+ echo PHP_EOL;
197
+ echo " ❌ " . $this->translator->get('ADD_NOT_FOUND', ['name' => $packageAlias]) . PHP_EOL;
198
+ echo PHP_EOL;
199
+ $this->showAvailablePackages();
200
+ return;
201
+ }
202
+
203
+ $package = $this->registry[$packageAlias];
204
+ $composerName = $package['composer'];
205
+
206
+ // ── Composer kontrolü ────────────────────────────────────
207
+ if (!$this->isComposerInstalled()) {
208
+ echo PHP_EOL;
209
+ echo " ❌ " . $this->translator->get('COMPOSER_MISSING_TITLE') . PHP_EOL;
210
+ return;
211
+ }
212
+
213
+ // ── composer.json kontrolü ───────────────────────────────
214
+ $projectRoot = getcwd();
215
+ if (!file_exists($projectRoot . '/composer.json')) {
216
+ echo PHP_EOL;
217
+ echo " ❌ " . $this->translator->get('ADD_NO_PROJECT') . PHP_EOL;
218
+ return;
219
+ }
220
+
221
+ // ── Zaten kurulu mu? ─────────────────────────────────────
222
+ if ($this->isAlreadyInstalled($projectRoot, $composerName)) {
223
+ echo PHP_EOL;
224
+ echo " ⚠️ " . $this->translator->get('ADD_ALREADY', ['name' => $packageAlias]) . PHP_EOL;
225
+ return;
226
+ }
227
+
228
+ // ── Kurulum başlasın ─────────────────────────────────────
229
+ echo PHP_EOL;
230
+ echo " 📦 " . $this->translator->get('ADD_INSTALLING', ['name' => $packageAlias, 'composer' => $composerName]) . PHP_EOL;
231
+ echo PHP_EOL;
232
+
233
+ $command = 'composer require ' . escapeshellarg($composerName);
234
+ $exitCode = 0;
235
+ passthru($command, $exitCode);
236
+
237
+ if ($exitCode !== 0) {
238
+ echo PHP_EOL;
239
+ echo " ❌ " . $this->translator->get('ADD_FAILED', ['name' => $packageAlias]) . PHP_EOL;
240
+ return;
241
+ }
242
+
243
+ // ── Entegrasyonlu paket ise ek işlemler ──────────────────
244
+ if ($package['type'] === 'integrated') {
245
+ $this->copyServiceStub($projectRoot, $package, $packageAlias);
246
+ $this->appendEnvVariables($projectRoot, $package, $packageAlias);
247
+ }
248
+
249
+ // ── Başarılı ─────────────────────────────────────────────
250
+ echo PHP_EOL;
251
+ echo " ╔══════════════════════════════════════════════════╗" . PHP_EOL;
252
+ echo " ║ ✅ " . $this->translator->get('ADD_SUCCESS', ['name' => $packageAlias, 'composer' => $composerName]) . PHP_EOL;
253
+ echo " ╚══════════════════════════════════════════════════╝" . PHP_EOL;
254
+
255
+ if ($package['type'] === 'integrated') {
256
+ echo PHP_EOL;
257
+ echo " 📄 " . $this->translator->get('ADD_SERVICE_CREATED', ['path' => $package['service']]) . PHP_EOL;
258
+ echo " 🔑 " . $this->translator->get('ADD_ENV_UPDATED') . PHP_EOL;
259
+ echo " ⚙️ " . $this->translator->get('ADD_EDIT_ENV') . PHP_EOL;
260
+ }
261
+
262
+ echo PHP_EOL;
263
+ }
264
+
265
+ // ─── Servis Sınıfı Kopyalama ─────────────────────────────────
266
+
267
+ /**
268
+ * CLI'daki stub dosyasını projenin içine kopyalar.
269
+ */
270
+ private function copyServiceStub(string $projectRoot, array $package, string $alias): void
271
+ {
272
+ $stubPath = \ARTIFRAME_CLI_ROOT . '/core-stubs/stubs/service/' . $package['stub'];
273
+ $targetPath = $projectRoot . '/' . $package['service'];
274
+
275
+ if (!file_exists($stubPath)) {
276
+ echo " ⚠️ " . $this->translator->get('ADD_STUB_MISSING', ['name' => $alias]) . PHP_EOL;
277
+ return;
278
+ }
279
+
280
+ // Hedef dizini oluştur
281
+ $targetDir = dirname($targetPath);
282
+ if (!is_dir($targetDir)) {
283
+ mkdir($targetDir, 0755, true);
284
+ }
285
+
286
+ // Zaten varsa üzerine yazma
287
+ if (file_exists($targetPath)) {
288
+ echo " ⚠️ " . $this->translator->get('ADD_SERVICE_EXISTS', ['path' => $package['service']]) . PHP_EOL;
289
+ return;
290
+ }
291
+
292
+ copy($stubPath, $targetPath);
293
+ }
294
+
295
+ // ─── .env Değişkenleri Ekleme ────────────────────────────────
296
+
297
+ /**
298
+ * .env ve .env.example dosyalarına gerekli anahtarları ekler.
299
+ */
300
+ private function appendEnvVariables(string $projectRoot, array $package, string $alias): void
301
+ {
302
+ if (empty($package['env'])) {
303
+ return;
304
+ }
305
+
306
+ $envBlock = PHP_EOL . implode(PHP_EOL, $package['env']) . PHP_EOL;
307
+
308
+ // .env dosyasına ekle
309
+ $envFile = $projectRoot . '/.env';
310
+ if (file_exists($envFile)) {
311
+ // Zaten eklenmişse tekrar ekleme
312
+ $currentContent = file_get_contents($envFile);
313
+ if (str_contains($currentContent, $package['env'][0])) {
314
+ return; // Başlık satırı zaten var, atla
315
+ }
316
+ file_put_contents($envFile, $envBlock, FILE_APPEND);
317
+ }
318
+
319
+ // .env.example dosyasına ekle
320
+ $envExample = $projectRoot . '/.env.example';
321
+ if (file_exists($envExample)) {
322
+ $currentContent = file_get_contents($envExample);
323
+ if (!str_contains($currentContent, $package['env'][0])) {
324
+ file_put_contents($envExample, $envBlock, FILE_APPEND);
325
+ }
326
+ }
327
+ }
328
+
329
+ // ─── Yardımcı Metodlar ───────────────────────────────────────
330
+
331
+ /**
332
+ * Paketin zaten kurulu olup olmadığını kontrol eder.
333
+ */
334
+ private function isAlreadyInstalled(string $projectRoot, string $composerName): bool
335
+ {
336
+ $lockFile = $projectRoot . '/composer.lock';
337
+ if (!file_exists($lockFile)) {
338
+ return false;
339
+ }
340
+ $lockContent = file_get_contents($lockFile);
341
+ return str_contains($lockContent, '"' . $composerName . '"');
342
+ }
343
+
344
+ /**
345
+ * Kayıtlı tüm paketleri kategorili bir şekilde listeler.
346
+ */
347
+ private function showAvailablePackages(): void
348
+ {
349
+ $g = "\033[38;2;0;157;108m"; // green
350
+ $y = "\033[38;5;220m"; // yellow
351
+ $d = "\033[38;2;100;100;100m"; // dim
352
+ $c = "\033[38;5;81m"; // cyan
353
+ $w = "\033[1;37m"; // white bold
354
+ $r = "\033[0m"; // reset
355
+
356
+ echo PHP_EOL;
357
+ echo " " . $w . $this->translator->get('ADD_LIST_TITLE') . $r . PHP_EOL;
358
+ echo " " . $d . "─────────────────────────────────────────────────────────────" . $r . PHP_EOL;
359
+ echo PHP_EOL;
360
+
361
+ // Entegrasyonlu Paketler
362
+ echo " " . $y . "⚡ " . $this->translator->get('ADD_CAT_INTEGRATED') . $r . PHP_EOL;
363
+ echo PHP_EOL;
364
+
365
+ foreach ($this->registry as $alias => $info) {
366
+ if ($info['type'] === 'integrated') {
367
+ $service = $info['service'] ?? '';
368
+ echo " " . $g . " add " . $alias . $r . $d . str_repeat(' ', max(1, 16 - strlen($alias))) . $info['composer'] . " → " . $service . $r . PHP_EOL;
369
+ }
370
+ }
371
+
372
+ echo PHP_EOL;
373
+
374
+ // Direkt Paketler
375
+ echo " " . $c . "📦 " . $this->translator->get('ADD_CAT_DIRECT') . $r . PHP_EOL;
376
+ echo PHP_EOL;
377
+
378
+ foreach ($this->registry as $alias => $info) {
379
+ if ($info['type'] === 'direct') {
380
+ echo " " . $g . " add " . $alias . $r . $d . str_repeat(' ', max(1, 16 - strlen($alias))) . $info['composer'] . $r . PHP_EOL;
381
+ }
382
+ }
383
+
384
+ echo PHP_EOL;
385
+ }
386
+
387
+ private function isComposerInstalled(): bool
388
+ {
389
+ $check = shell_exec('composer --version 2>&1');
390
+ return $check !== null && str_contains($check, 'Composer');
391
+ }
392
+ }
@@ -0,0 +1,48 @@
1
+ <?php
2
+ namespace ArtiFrame\Cli\Commands;
3
+
4
+ use ArtiFrame\Cli\Services\Translator;
5
+
6
+ class GoCommand
7
+ {
8
+ private Translator $translator;
9
+
10
+ public function __construct(Translator $translator)
11
+ {
12
+ $this->translator = $translator;
13
+ }
14
+
15
+ public function execute(array $args): void
16
+ {
17
+ $target = $args[0] ?? null;
18
+
19
+ if (!$target) {
20
+ echo "
21
+ ❌ " . $this->translator->get('GO_MISSING_DIR') . "
22
+
23
+ ";
24
+ return;
25
+ }
26
+
27
+ if ($target === 'back') {
28
+ $target = '..';
29
+ }
30
+
31
+ if (!is_dir($target)) {
32
+ $notFound = str_replace(':dir', $target, $this->translator->get('GO_NOT_FOUND'));
33
+ echo "
34
+ ❌ " . $notFound . "
35
+
36
+ ";
37
+ return;
38
+ }
39
+
40
+ chdir($target);
41
+ echo "
42
+ ✅ " . $this->translator->get('GO_SUCCESS') . "
43
+ ";
44
+ echo " " . getcwd() . "
45
+
46
+ ";
47
+ }
48
+ }
@@ -0,0 +1,67 @@
1
+ <?php
2
+ namespace ArtiFrame\Cli\Commands;
3
+
4
+ use ArtiFrame\Cli\Services\Translator;
5
+
6
+ class ListCommand
7
+ {
8
+ private Translator $translator;
9
+
10
+ public function __construct(Translator $translator)
11
+ {
12
+ $this->translator = $translator;
13
+ }
14
+
15
+ public function execute(array $args): void
16
+ {
17
+ $dir = getcwd();
18
+ $projectName = basename($dir);
19
+
20
+ echo "
21
+ 📂 " . $projectName . "/
22
+ ";
23
+
24
+ $priorityOrder = [
25
+ 'bin', 'config', 'src', 'app', 'public', '.agents',
26
+ 'vendor', '.env', '.env.example', '.gitignore',
27
+ 'composer.json', 'composer.lock', 'schema.sql',
28
+ 'README.md', 'OKUBENI.md', 'LESEMICH.md', 'LISEZMOI.md', 'LEAME.md',
29
+ 'kilavuz.html', 'guide.html', 'handbuch.html', 'guide_fr.html', 'guia.html', 'LICENSE',
30
+ ];
31
+
32
+ $entries = array_filter(scandir($dir), fn($e) => $e !== '.' && $e !== '..');
33
+
34
+ usort($entries, function ($a, $b) use ($priorityOrder) {
35
+ $ia = array_search($a, $priorityOrder);
36
+ $ib = array_search($b, $priorityOrder);
37
+ $ia = ($ia === false) ? 99 : $ia;
38
+ $ib = ($ib === false) ? 99 : $ib;
39
+ return $ia <=> $ib;
40
+ });
41
+
42
+ $entries = array_values($entries);
43
+ $total = count($entries);
44
+
45
+ foreach ($entries as $i => $entry) {
46
+ $isLast = ($i === $total - 1);
47
+ $connector = $isLast ? '└──' : '├──';
48
+ $fullPath = $dir . DIRECTORY_SEPARATOR . $entry;
49
+
50
+ if (is_dir($fullPath)) {
51
+ $subItems = array_filter(scandir($fullPath), fn($e) => $e !== '.' && $e !== '..');
52
+ $subCount = count($subItems);
53
+ $countStr = $subCount > 0 ? ' ' . $this->translator->get('DIR_ITEM_COUNT', ['count' => $subCount]) : '';
54
+ echo " │ {$connector} 📂 {$entry}/{$countStr}
55
+ ";
56
+ } else {
57
+ $size = filesize($fullPath);
58
+ $sizeStr = $size > 1024 ? round($size / 1024, 1) . ' KB' : $size . ' B';
59
+ echo " │ {$connector} 📄 {$entry} [{$sizeStr}]
60
+ ";
61
+ }
62
+ }
63
+ echo " │
64
+
65
+ ";
66
+ }
67
+ }