Skip to content

Commit 5eb3df0

Browse files
committed
Merge branch 'master' into fix-for-pg-complain-about-empty-queries
2 parents 6a1e1ee + 76993b8 commit 5eb3df0

File tree

6 files changed

+223
-3
lines changed

6 files changed

+223
-3
lines changed

src/BackpackServiceProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class BackpackServiceProvider extends ServiceProvider
2121
\Backpack\CRUD\app\Console\Commands\CreateUser::class,
2222
\Backpack\CRUD\app\Console\Commands\PublishBackpackMiddleware::class,
2323
\Backpack\CRUD\app\Console\Commands\PublishView::class,
24+
\Backpack\CRUD\app\Console\Commands\RequireDevTools::class,
2425
];
2526

2627
// Indicates if loading of the provider is deferred.

src/app/Console/Commands/Install.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,14 @@ public function handle()
5757

5858
$this->progressBar->finish();
5959
$this->info(' Backpack installation finished.');
60+
61+
// DevTools
62+
$this->box('Did you know about Backpack DevTools?');
63+
$this->note('DevTools adds a dead-simple web interface to easily generate Models, Migrations, Seeders, Factories, CRUDs, etc.');
64+
$this->note('But it\'s a paid tool. For more info, payment and access, please visit https://backpackforlaravel.com/products/devtools');
65+
66+
if ($this->confirm('Would you like to install Backpack DevTools?', false)) {
67+
$this->call('backpack:require:devtools');
68+
}
6069
}
6170
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
<?php
2+
3+
namespace Backpack\CRUD\app\Console\Commands;
4+
5+
use File;
6+
use Illuminate\Console\Command;
7+
use Str;
8+
use Symfony\Component\Process\Process;
9+
10+
class RequireDevTools extends Command
11+
{
12+
use \Backpack\CRUD\app\Console\Commands\Traits\PrettyCommandOutput;
13+
14+
protected $progressBar;
15+
16+
/**
17+
* The name and signature of the console command.
18+
*
19+
* @var string
20+
*/
21+
protected $signature = 'backpack:require:devtools
22+
{--debug} : Show process output or not. Useful for debugging.';
23+
24+
/**
25+
* The console command description.
26+
*
27+
* @var string
28+
*/
29+
protected $description = 'Require Backpack DevTools on dev.';
30+
31+
/**
32+
* Execute the console command.
33+
*
34+
* @return mixed Command-line output
35+
*/
36+
public function handle()
37+
{
38+
$this->progressBar = $this->output->createProgressBar(29);
39+
$this->progressBar->minSecondsBetweenRedraws(0);
40+
$this->progressBar->maxSecondsBetweenRedraws(120);
41+
$this->progressBar->setRedrawFrequency(1);
42+
43+
$this->progressBar->start();
44+
45+
$this->info(' Requiring DevTools. Please wait...');
46+
$this->progressBar->advance();
47+
48+
// Check if auth exists
49+
$details = null;
50+
$process = new Process(['composer', 'config', 'http-basic.backpackforlaravel.com']);
51+
$process->run(function ($type, $buffer) use (&$details) {
52+
if ($type !== Process::ERR && $buffer !== '') {
53+
$details = json_decode($buffer);
54+
} elseif (File::exists('auth.json')) {
55+
$details = json_decode(File::get('auth.json'), true)['http-basic']['backpackforlaravel.com'] ?? false;
56+
}
57+
$this->progressBar->advance();
58+
});
59+
60+
// Create an auth.json file
61+
if (! $details) {
62+
$this->info(' Creating auth.json file with your authentication token');
63+
64+
$this->line(' (Find your access token details on https://backpackforlaravel.com/user/tokens)');
65+
$username = $this->ask('Access token username');
66+
$password = $this->ask('Access token password');
67+
68+
$process = new Process(['composer', 'config', 'http-basic.backpackforlaravel.com', $username, $password]);
69+
$process->run(function ($type, $buffer) use ($username, $password) {
70+
if ($type === Process::ERR) {
71+
// Fallback
72+
$authFile = [
73+
'http-basic' => [
74+
'backpackforlaravel.com' => [
75+
'username' => $username,
76+
'password' => $password,
77+
],
78+
],
79+
];
80+
81+
if (File::exists('auth.json')) {
82+
$currentFile = json_decode(File::get('auth.json'), true);
83+
if (! ($currentFile['http-basic']['backpackforlaravel.com'] ?? false)) {
84+
$authFile = array_merge_recursive($authFile, $currentFile);
85+
}
86+
}
87+
88+
File::put('auth.json', json_encode($authFile, JSON_PRETTY_PRINT));
89+
}
90+
$this->progressBar->advance();
91+
});
92+
}
93+
94+
// Check if repositories exists
95+
$details = null;
96+
$process = new Process(['composer', 'config', 'repositories.backpack/devtools']);
97+
$process->run(function ($type, $buffer) use (&$details) {
98+
if ($type !== Process::ERR && $buffer !== '') {
99+
$details = json_decode($buffer);
100+
} else {
101+
$details = json_decode(File::get('composer.json'), true)['repositories']['backpack/devtools'] ?? false;
102+
}
103+
$this->progressBar->advance();
104+
});
105+
106+
// Create repositories
107+
if (! $details) {
108+
$this->info(' Creating repositories entry in composer.json');
109+
110+
$process = new Process(['composer', 'config', 'repositories.backpack/devtools', 'composer', 'https://repo.backpackforlaravel.com']);
111+
$process->run(function ($type, $buffer) {
112+
if ($type === Process::ERR) {
113+
// Fallback
114+
$composerJson = Str::of(File::get('composer.json'));
115+
116+
$currentRepositories = json_decode($composerJson, true)['repositories'] ?? false;
117+
118+
$repositories = Str::of(json_encode([
119+
'repositories' => [
120+
'backpack/devtools' => [
121+
'type' => 'composer',
122+
'url' => 'https://repo.backpackforlaravel.com',
123+
],
124+
],
125+
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
126+
127+
$composerJson = $currentRepositories
128+
// Replace current repositories
129+
? preg_replace('/"repositories":\s{\r?\n/', $repositories->match("/\{\n\s+([\s\S]+)\n\s{4}\}/m")->append(",\n"), $composerJson)
130+
// Append to the end of the file
131+
: preg_replace("/\r?\n}/", $repositories->replaceFirst('{', ','), $composerJson);
132+
133+
File::put('composer.json', $composerJson);
134+
}
135+
$this->progressBar->advance();
136+
});
137+
}
138+
139+
// Require package
140+
$process = new Process(['composer', 'require', '--dev', '--with-all-dependencies', 'backpack/devtools']);
141+
$process->setTimeout(300);
142+
$process->run(function ($type, $buffer) {
143+
$this->progressBar->advance();
144+
});
145+
146+
// Finish
147+
$this->progressBar->finish();
148+
$this->info(' DevTools is now required.');
149+
150+
// DevTools inside installer
151+
$this->info('');
152+
$this->info(' Now running the DevTools installation command.');
153+
154+
// manually include the command in the run-time
155+
if (! class_exists(\Backpack\DevTools\Console\Commands\InstallDevTools::class)) {
156+
include base_path('vendor/backpack/devtools/src/Console/Commands/InstallDevTools.php');
157+
}
158+
159+
$this->call(\Backpack\DevTools\Console\Commands\InstallDevTools::class);
160+
}
161+
}

src/app/Console/Commands/Traits/PrettyCommandOutput.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,29 @@ public function echo($type, $content)
9494
$this->{$type}($content);
9595
}
9696
}
97+
98+
/**
99+
* Write a title inside a box.
100+
*
101+
* @param string $content
102+
*/
103+
public function box($content)
104+
{
105+
for ($i = 0, $line = ''; $i < strlen($content); ++$i, $line .= '');
106+
107+
$this->line('');
108+
$this->info("┌───{$line}───┐");
109+
$this->info("$content");
110+
$this->info("└───{$line}───┘");
111+
}
112+
113+
/**
114+
* Write a title inside a box.
115+
*
116+
* @param string $content
117+
*/
118+
public function note($content)
119+
{
120+
$this->line("$content");
121+
}
97122
}

src/app/Library/CrudPanel/CrudPanel.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,4 +488,22 @@ private function getRelatedEntries($model, $relationString)
488488

489489
return $results;
490490
}
491+
492+
/**
493+
* Check if the method in the given model has any parameters.
494+
*
495+
* @param object $model
496+
* @param string $method
497+
* @return bool
498+
*/
499+
private function modelMethodHasParameters($model, $method)
500+
{
501+
$reflectClassMethod = new \ReflectionMethod(get_class($model), $method);
502+
503+
if ($reflectClassMethod->getNumberOfParameters() > 0) {
504+
return true;
505+
}
506+
507+
return false;
508+
}
491509
}

src/app/Library/CrudPanel/Traits/ColumnsProtectedMethods.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,19 @@ protected function makeSureColumnHasEntity($column)
146146
// if the first part of the string exists as method,
147147
// it is a relationship
148148
if (method_exists($this->model, $possibleMethodName)) {
149-
$column['entity'] = $column['name'];
149+
150+
// if it has parameters it's not a relation method.
151+
$column['entity'] = $this->modelMethodHasParameters($this->model, $possibleMethodName) ? false : $column['name'];
150152

151153
return $column;
152154
}
153155
}
154156

155157
// if there's a method on the model with this name
156158
if (method_exists($this->model, $column['name'])) {
157-
$column['entity'] = $column['name'];
159+
160+
// if it has parameters it's not a relation method.
161+
$column['entity'] = $this->modelMethodHasParameters($this->model, $column['name']) ? false : $column['name'];
158162

159163
return $column;
160164
}
@@ -165,7 +169,9 @@ protected function makeSureColumnHasEntity($column)
165169
$possibleMethodName = Str::replaceLast('_id', '', $column['name']);
166170

167171
if (method_exists($this->model, $possibleMethodName)) {
168-
$column['entity'] = $possibleMethodName;
172+
173+
// if it has parameters it's not a relation method.
174+
$column['entity'] = $this->modelMethodHasParameters($this->model, $possibleMethodName) ? false : $possibleMethodName;
169175

170176
return $column;
171177
}

0 commit comments

Comments
 (0)