%PDF- %PDF-
Direktori : /home/silvzytp/crm-ind-code/vendor/laravel/framework/src/Illuminate/Foundation/Console/ |
Current File : //home/silvzytp/crm-ind-code/vendor/laravel/framework/src/Illuminate/Foundation/Console/ShowModelCommand.php |
<?php namespace Illuminate\Foundation\Console; use BackedEnum; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\Index; use Doctrine\DBAL\Types\DecimalType; use Illuminate\Console\Command; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Database\Console\DatabaseInspectionCommand; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Facades\Gate; use Illuminate\Support\Str; use ReflectionClass; use ReflectionMethod; use SplFileObject; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Output\OutputInterface; use UnitEnum; #[AsCommand(name: 'model:show')] class ShowModelCommand extends DatabaseInspectionCommand { /** * The console command name. * * @var string */ protected $name = 'model:show {model}'; /** * The name of the console command. * * This name is used to identify the command during lazy loading. * * @var string|null * * @deprecated */ protected static $defaultName = 'model:show'; /** * The console command description. * * @var string */ protected $description = 'Show information about an Eloquent model'; /** * The console command signature. * * @var string */ protected $signature = 'model:show {model : The model to show} {--database= : The database connection to use} {--json : Output the model as JSON}'; /** * The methods that can be called in a model to indicate a relation. * * @var array */ protected $relationMethods = [ 'hasMany', 'hasManyThrough', 'hasOneThrough', 'belongsToMany', 'hasOne', 'belongsTo', 'morphOne', 'morphTo', 'morphMany', 'morphToMany', 'morphedByMany', ]; /** * Execute the console command. * * @return void */ public function handle() { if (! $this->ensureDependenciesExist()) { return 1; } $class = $this->qualifyModel($this->argument('model')); try { $model = $this->laravel->make($class); $class = get_class($model); } catch (BindingResolutionException $e) { return $this->components->error($e->getMessage()); } if ($this->option('database')) { $model->setConnection($this->option('database')); } $this->display( $class, $model->getConnection()->getName(), $model->getConnection()->getTablePrefix().$model->getTable(), $this->getPolicy($model), $this->getAttributes($model), $this->getRelations($model), $this->getObservers($model), ); } /** * Get the first policy associated with this model. * * @param \Illuminate\Database\Eloquent\Model $model * @return Illuminate\Support\Collection */ protected function getPolicy($model) { return collect(Gate::policies()) ->filter(fn ($policy, $modelClass) => $modelClass === get_class($model)) ->values() ->first(); } /** * Get the column attributes for the given model. * * @param \Illuminate\Database\Eloquent\Model $model * @return \Illuminate\Support\Collection */ protected function getAttributes($model) { $schema = $model->getConnection()->getDoctrineSchemaManager(); $this->registerTypeMappings($schema->getDatabasePlatform()); $table = $model->getConnection()->getTablePrefix().$model->getTable(); $columns = $schema->listTableColumns($table); $indexes = $schema->listTableIndexes($table); return collect($columns) ->values() ->map(fn (Column $column) => [ 'name' => $column->getName(), 'type' => $this->getColumnType($column), 'increments' => $column->getAutoincrement(), 'nullable' => ! $column->getNotnull(), 'default' => $this->getColumnDefault($column, $model), 'unique' => $this->columnIsUnique($column->getName(), $indexes), 'fillable' => $model->isFillable($column->getName()), 'hidden' => $this->attributeIsHidden($column->getName(), $model), 'appended' => null, 'cast' => $this->getCastType($column->getName(), $model), ]) ->merge($this->getVirtualAttributes($model, $columns)); } /** * Get the virtual (non-column) attributes for the given model. * * @param \Illuminate\Database\Eloquent\Model $model * @param \Doctrine\DBAL\Schema\Column[] $columns * @return \Illuminate\Support\Collection */ protected function getVirtualAttributes($model, $columns) { $class = new ReflectionClass($model); return collect($class->getMethods()) ->reject( fn (ReflectionMethod $method) => $method->isStatic() || $method->isAbstract() || $method->getDeclaringClass()->getName() !== get_class($model) ) ->mapWithKeys(function (ReflectionMethod $method) use ($model) { if (preg_match('/^get(.+)Attribute$/', $method->getName(), $matches) === 1) { return [Str::snake($matches[1]) => 'accessor']; } elseif ($model->hasAttributeMutator($method->getName())) { return [Str::snake($method->getName()) => 'attribute']; } else { return []; } }) ->reject(fn ($cast, $name) => collect($columns)->has($name)) ->map(fn ($cast, $name) => [ 'name' => $name, 'type' => null, 'increments' => false, 'nullable' => null, 'default' => null, 'unique' => null, 'fillable' => $model->isFillable($name), 'hidden' => $this->attributeIsHidden($name, $model), 'appended' => $model->hasAppended($name), 'cast' => $cast, ]) ->values(); } /** * Get the relations from the given model. * * @param \Illuminate\Database\Eloquent\Model $model * @return \Illuminate\Support\Collection */ protected function getRelations($model) { return collect(get_class_methods($model)) ->map(fn ($method) => new ReflectionMethod($model, $method)) ->reject( fn (ReflectionMethod $method) => $method->isStatic() || $method->isAbstract() || $method->getDeclaringClass()->getName() !== get_class($model) ) ->filter(function (ReflectionMethod $method) { $file = new SplFileObject($method->getFileName()); $file->seek($method->getStartLine() - 1); $code = ''; while ($file->key() < $method->getEndLine()) { $code .= $file->current(); $file->next(); } return collect($this->relationMethods) ->contains(fn ($relationMethod) => str_contains($code, '$this->'.$relationMethod.'(')); }) ->map(function (ReflectionMethod $method) use ($model) { $relation = $method->invoke($model); if (! $relation instanceof Relation) { return null; } return [ 'name' => $method->getName(), 'type' => Str::afterLast(get_class($relation), '\\'), 'related' => get_class($relation->getRelated()), ]; }) ->filter() ->values(); } /** * Get the Observers watching this model. * * @param \Illuminate\Database\Eloquent\Model $model * @return Illuminate\Support\Collection */ protected function getObservers($model) { $listeners = $this->getLaravel()->make('events')->getRawListeners(); // Get the Eloquent observers for this model... $listeners = array_filter($listeners, function ($v, $key) use ($model) { return Str::startsWith($key, 'eloquent.') && Str::endsWith($key, $model::class); }, ARRAY_FILTER_USE_BOTH); // Format listeners Eloquent verb => Observer methods... $extractVerb = function ($key) { preg_match('/eloquent.([a-zA-Z]+)\: /', $key, $matches); return $matches[1] ?? '?'; }; $formatted = []; foreach ($listeners as $key => $observerMethods) { $formatted[] = [ 'event' => $extractVerb($key), 'observer' => array_map(fn ($obs) => is_string($obs) ? $obs : 'Closure', $observerMethods), ]; } return collect($formatted); } /** * Render the model information. * * @param string $class * @param string $database * @param string $table * @param string $policy * @param \Illuminate\Support\Collection $attributes * @param \Illuminate\Support\Collection $relations * @param \Illuminate\Support\Collection $observers * @return void */ protected function display($class, $database, $table, $policy, $attributes, $relations, $observers) { $this->option('json') ? $this->displayJson($class, $database, $table, $policy, $attributes, $relations, $observers) : $this->displayCli($class, $database, $table, $policy, $attributes, $relations, $observers); } /** * Render the model information as JSON. * * @param string $class * @param string $database * @param string $table * @param string $policy * @param \Illuminate\Support\Collection $attributes * @param \Illuminate\Support\Collection $relations * @param \Illuminate\Support\Collection $observers * @return void */ protected function displayJson($class, $database, $table, $policy, $attributes, $relations, $observers) { $this->output->writeln( collect([ 'class' => $class, 'database' => $database, 'table' => $table, 'policy' => $policy, 'attributes' => $attributes, 'relations' => $relations, 'observers' => $observers, ])->toJson() ); } /** * Render the model information for the CLI. * * @param string $class * @param string $database * @param string $table * @param string $policy * @param \Illuminate\Support\Collection $attributes * @param \Illuminate\Support\Collection $relations * @param \Illuminate\Support\Collection $observers * @return void */ protected function displayCli($class, $database, $table, $policy, $attributes, $relations, $observers) { $this->newLine(); $this->components->twoColumnDetail('<fg=green;options=bold>'.$class.'</>'); $this->components->twoColumnDetail('Database', $database); $this->components->twoColumnDetail('Table', $table); if ($policy) { $this->components->twoColumnDetail('Policy', $policy); } $this->newLine(); $this->components->twoColumnDetail( '<fg=green;options=bold>Attributes</>', 'type <fg=gray>/</> <fg=yellow;options=bold>cast</>', ); foreach ($attributes as $attribute) { $first = trim(sprintf( '%s %s', $attribute['name'], collect(['increments', 'unique', 'nullable', 'fillable', 'hidden', 'appended']) ->filter(fn ($property) => $attribute[$property]) ->map(fn ($property) => sprintf('<fg=gray>%s</>', $property)) ->implode('<fg=gray>,</> ') )); $second = collect([ $attribute['type'], $attribute['cast'] ? '<fg=yellow;options=bold>'.$attribute['cast'].'</>' : null, ])->filter()->implode(' <fg=gray>/</> '); $this->components->twoColumnDetail($first, $second); if ($attribute['default'] !== null) { $this->components->bulletList( [sprintf('default: %s', $attribute['default'])], OutputInterface::VERBOSITY_VERBOSE ); } } $this->newLine(); $this->components->twoColumnDetail('<fg=green;options=bold>Relations</>'); foreach ($relations as $relation) { $this->components->twoColumnDetail( sprintf('%s <fg=gray>%s</>', $relation['name'], $relation['type']), $relation['related'] ); } $this->newLine(); $this->components->twoColumnDetail('<fg=green;options=bold>Observers</>'); if ($observers->count()) { foreach ($observers as $observer) { $this->components->twoColumnDetail( sprintf('%s', $observer['event']), implode(', ', $observer['observer']) ); } } $this->newLine(); } /** * Get the cast type for the given column. * * @param string $column * @param \Illuminate\Database\Eloquent\Model $model * @return string|null */ protected function getCastType($column, $model) { if ($model->hasGetMutator($column) || $model->hasSetMutator($column)) { return 'accessor'; } if ($model->hasAttributeMutator($column)) { return 'attribute'; } return $this->getCastsWithDates($model)->get($column) ?? null; } /** * Get the model casts, including any date casts. * * @param \Illuminate\Database\Eloquent\Model $model * @return \Illuminate\Support\Collection */ protected function getCastsWithDates($model) { return collect($model->getDates()) ->filter() ->flip() ->map(fn () => 'datetime') ->merge($model->getCasts()); } /** * Get the type of the given column. * * @param \Doctrine\DBAL\Schema\Column $column * @return string */ protected function getColumnType($column) { $name = $column->getType()->getName(); $unsigned = $column->getUnsigned() ? ' unsigned' : ''; $details = match (get_class($column->getType())) { DecimalType::class => $column->getPrecision().','.$column->getScale(), default => $column->getLength(), }; if ($details) { return sprintf('%s(%s)%s', $name, $details, $unsigned); } return sprintf('%s%s', $name, $unsigned); } /** * Get the default value for the given column. * * @param \Doctrine\DBAL\Schema\Column $column * @param \Illuminate\Database\Eloquent\Model $model * @return mixed|null */ protected function getColumnDefault($column, $model) { $attributeDefault = $model->getAttributes()[$column->getName()] ?? null; return match (true) { $attributeDefault instanceof BackedEnum => $attributeDefault->value, $attributeDefault instanceof UnitEnum => $attributeDefault->name, default => $attributeDefault ?? $column->getDefault(), }; } /** * Determine if the given attribute is hidden. * * @param string $attribute * @param \Illuminate\Database\Eloquent\Model $model * @return bool */ protected function attributeIsHidden($attribute, $model) { if (count($model->getHidden()) > 0) { return in_array($attribute, $model->getHidden()); } if (count($model->getVisible()) > 0) { return ! in_array($attribute, $model->getVisible()); } return false; } /** * Determine if the given attribute is unique. * * @param string $column * @param \Doctrine\DBAL\Schema\Index[] $indexes * @return bool */ protected function columnIsUnique($column, $indexes) { return collect($indexes) ->filter(fn (Index $index) => count($index->getColumns()) === 1 && $index->getColumns()[0] === $column) ->contains(fn (Index $index) => $index->isUnique()); } /** * Qualify the given model class base name. * * @param string $model * @return string * * @see \Illuminate\Console\GeneratorCommand */ protected function qualifyModel(string $model) { if (str_contains($model, '\\') && class_exists($model)) { return $model; } $model = ltrim($model, '\\/'); $model = str_replace('/', '\\', $model); $rootNamespace = $this->laravel->getNamespace(); if (Str::startsWith($model, $rootNamespace)) { return $model; } return is_dir(app_path('Models')) ? $rootNamespace.'Models\\'.$model : $rootNamespace.$model; } }