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
24 changes: 24 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Set default line ending behavior, in case people don't have core.autocrlf set
* text=auto

# Explicitly declare text files you want to always be normalized and converted to native line endings on checkout
*.php text eol=lf
*.json text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.yaml text eol=lf

# Denote all files that are truly binary and should not be modified
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pdf binary

# Composer files
/composer.lock -diff

# Git attributes for better diff and merge handling
*.stub text eol=lf

39 changes: 39 additions & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: PHP Composer

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

permissions:
contents: read

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Validate composer.json and composer.lock
run: composer validate --strict

- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-

- name: Install dependencies
run: composer install --prefer-dist --no-progress

# Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
# Docs: https://getcomposer.org/doc/articles/scripts.md

# - name: Run test suite
# run: composer run-script test
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# Kenernel243/Artisan
# Kernel243/Artisan

This package provides a set of new artisan commands for Laravel
[![Packagist Downloads](https://img.shields.io/packagist/dt/kernel243/artisan.svg?style=for-the-badge)](https://packagist.org/packages/kernel243/artisan)
[![Visits](https://badges.pufler.dev/visits/kernel243/artisan?style=for-the-badge)](https://packagist.org/packages/kernel243/artisan)

This package provides a set of new artisan commands for Laravel.

This package is based on another laravel package ``dannyvilla/artisan-commands``, my package adds other options which are not yet available in this one for example the use of a modular architecture with laravel ``nwidart/laravel-modules`` and many other options.

Visit the developer website: [developper.elongocrea.com](https://developper.elongocrea.com)

## Installation

Use the package manager [composer](https://getcomposer.org/) to install kernel243/artisan
Expand Down Expand Up @@ -86,6 +91,18 @@ php artisan make:class App\Contracts\IClassable --kind=interface
php artisan make:file folder.subfolder1.subfolder2.filename --ext=php
```

### CRUD command
Generate a CRUD with model, repository, service, controller and Tailwind views
```bash
php artisan make:crud Product --fields="title:string,description:text,price:decimal,is_active:boolean"
```

### Resource CRUD command
Generate CRUD using a Resource class (Filament-inspired)
```bash
php artisan make:resource-crud Product --fields="title:string,description:text"
```

## Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Expand Down
35 changes: 32 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,27 @@
"description": "This package provides a set of artisan commands for Laravel",
"type": "library",
"license": "MIT",
"keywords": [
"laravel",
"artisan",
"commands",
"generator",
"repository",
"service",
"controller",
"resource",
"stubs"
],
"autoload": {
"psr-4": {
"Kernel243\\Artisan\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Kernel243\\Artisan\\Tests\\": "tests/"
}
},
"extra": {
"laravel": {
"providers": [
Expand All @@ -21,9 +37,22 @@
"email": "merdielongo9@gmail.com"
}
],
"minimum-stability": "dev",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=7.4.0",
"laravel/framework": ">=5.8.0"
"php": "^8.0|^8.1|^8.2|^8.3",
"laravel/framework": "^8.0|^9.0|^10.0|^11.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0|^10.0",
"orchestra/testbench": "^6.0|^7.0|^8.0"
},
"scripts": {
"test": "phpunit",
"analyse": "phpstan analyse"
},
"config": {
"sort-packages": true,
"optimize-autoloader": true
}
}
31 changes: 14 additions & 17 deletions src/CommandServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,28 @@
namespace Kernel243\Artisan;

use Illuminate\Support\ServiceProvider;
use Kernel243\Artisan\Commands\Controller;
use Kernel243\Artisan\Commands\File;
use Kernel243\Artisan\Commands\Repository;
use Kernel243\Artisan\Commands\Resource;
use Kernel243\Artisan\Commands\Service;
use Kernel243\Artisan\Commands\View;

class CommandServiceProvider extends ServiceProvider {

class CommandServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
public function boot(): void
{
if ($this->app->runningInConsole()) {
$this->commands([
Repository::class,
Service::class,
File::class,
View::class,
Resource::class,
Controller::class
Commands\Repository::class,
Commands\Service::class,
Commands\File::class,
Commands\View::class,
Commands\Resource::class,
Commands\Controller::class,
Commands\Lang::class,
Commands\ClassMakeCommand::class,
Commands\CrudMakeCommand::class,
Commands\ResourceMakeCommand::class,
]);
}
}
Expand All @@ -36,9 +34,8 @@ public function boot()
*
* @return void
*/
public function register()
public function register(): void
{
//
}

}
92 changes: 81 additions & 11 deletions src/Commands/BaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ protected function moduleExists($module)
/**
* Checks if a folder exist and return canonicalized absolute pathname (sort version)
* @param string $folder the path being checked.
* @return mixed returns the canonicalized absolute pathname on success otherwise FALSE is returned
* @return string|false returns the canonicalized absolute pathname on success otherwise FALSE is returned
*/
protected function folderExist($folder)
protected function folderExist(string $folder)
{
// Get canonicalized absolute pathname
$path = realpath($folder);

// If it exists, check if it's a directory
return ($path !== false AND is_dir($path)) ? $path : false;
return ($path !== false && is_dir($path)) ? $path : false;
}

/**
Expand Down Expand Up @@ -134,6 +134,74 @@ protected function replaceResourceNamespace($namespace, $stub)
return str_replace('DummyNamespaceResource', ucfirst($namespace), $stub);
}

/**
* Read a stub file by logical name from this package stubs directory.
*/
protected function getStubContent(string $name): string
{
$path = __DIR__ . '/stubs/' . str_replace('.', '/', $name) . '.stub';
if (!file_exists($path)) {
throw new \RuntimeException('Stub not found: ' . $path);
}
return (string) file_get_contents($path);
}

/**
* Write content to a file, creating parent directories when needed.
*/
protected function writeFile(string $path, string $content): void
{
$dir = dirname($path);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
file_put_contents($path, $content);
}

/**
* Ask whether a file should be replaced unless --force is provided.
*/
protected function shouldReplaceFile(string $path, string $question = 'Replace file? [y/n]'): bool
{
if (!file_exists($path)) {
return true;
}
if ($this->option('force')) {
return true;
}
do {
$input = strtolower($this->ask($question));
} while ($input !== 'y' && $input !== 'n');
return $input === 'y';
}

/**
* Simple success output helper.
*/
protected function displaySuccess(string $message, string $path): void
{
$this->info($message);
$this->line(' → ' . $path);
}

/**
* Ensure a directory exists.
*/
protected function ensureDirectoryExists(string $directory): void
{
if (!file_exists($directory)) {
mkdir($directory, 0755, true);
}
}

/**
* Basic filename validation for ClassMakeCommand.
*/
protected function isValidFilename(string $filename): bool
{
return (bool) preg_match('#^[A-Za-z0-9_\\\\/\.-]+$#', $filename);
}

/**
* Check if a repository file exists.
*
Expand All @@ -144,11 +212,12 @@ protected function replaceResourceNamespace($namespace, $stub)
protected function repositoryFileExists($repository, $module = null): bool
{
if (is_null($module)) {
return file_exists( base_path(lcfirst($repository).'.php')) || file_exists( base_path(lcfirst(str_replace('\\', '/', $repository)).'.php'));
$repositoryName = ucfirst(basename(str_replace('\\', '/', $repository)));
return file_exists(app_path('Repositories/'.$repositoryName.'.php'));
}

$path = base_path('Modules/'.ucfirst($module).'/Repositories/'.lcfirst($repository).'.php');
return file_exists($path) || file_exists('Modules/'.base_path(ucfirst($module).'/Repositories/'.lcfirst(str_replace('\\', '/', $repository)).'.php'));
$path = base_path('Modules/'.ucfirst($module).'/Repositories/'.ucfirst(basename(str_replace('\\', '/', $repository))).'.php');
return file_exists($path);
}

/**
Expand All @@ -167,7 +236,7 @@ protected function setModelAndNamespace(&$model, &$namespace, &$module)
$module = '';

for ($i = 0; $i < count($exploded) - 1; $i++) {
if (!isEmpty($module)) {
if (!empty($module)) {
$namespace .= $module.'\\'.$exploded[$i].'\\'.'Entities\\';
} else {
$namespace .= $exploded[$i].'\\';
Expand All @@ -193,7 +262,7 @@ protected function setRepositoryAndNamespace(&$repository, &$namespace, &$module
$module = '';

for ($i = 0; $i < count($exploded) - 1; $i++) {
if (!isEmpty($module)) {
if (!empty($module)) {
$namespace .= $module.'\\'.$exploded[$i].'\\'.'Repositories\\';
} else {
$namespace .= $exploded[$i].'\\';
Expand All @@ -213,11 +282,12 @@ protected function setRepositoryAndNamespace(&$repository, &$namespace, &$module
protected function modelFileExists($model, $module = null): bool
{
if (is_null($module)) {
return file_exists( base_path(lcfirst($model).'.php')) || file_exists( base_path(lcfirst(str_replace('\\', '/', $model)).'.php'));
$modelName = ucfirst(basename(str_replace('\\', '/', $model)));
return file_exists(app_path('Models/'.$modelName.'.php'));
}

$path = base_path('Modules/'.ucfirst($module).'/Entities/'.lcfirst($model).'.php');
return file_exists($path) || file_exists('Modules/'.base_path(ucfirst($module).'/Entities/'.lcfirst(str_replace('\\', '/', $model)).'.php'));
$path = base_path('Modules/'.ucfirst($module).'/Entities/'.ucfirst(basename(str_replace('\\', '/', $model))).'.php');
return file_exists($path);
}


Expand Down
Loading