Commit e79087a3 authored by Dillenn Terumalai's avatar Dillenn Terumalai
Browse files

Initial commit

parents
# Path-based git attributes
# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
# Ignore all test and documentation with "export-ignore".
/.github export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/phpunit.xml.dist export-ignore
/tests export-ignore
/.editorconfig export-ignore
/.php_cs.dist export-ignore
/psalm.xml export-ignore
/psalm.xml.dist export-ignore
\ No newline at end of file
.DS_Store
.idea
.phpunit.result.cache
build
composer.lock
coverage
docs
phpunit.xml
vendor
\ No newline at end of file
image: php:8
before_script:
- bash ci/docker_install.sh > /dev/null
test:package:
script:
- phpunit --configuration phpunit.xml
publish:package:
image: curlimages/curl:latest
stage: build
variables:
URL: "$CI_SERVER_PROTOCOL://$CI_SERVER_HOST:$CI_SERVER_PORT/api/v4/projects/$CI_PROJECT_ID/packages/composer?job_token=$CI_JOB_TOKEN"
script:
- version=$([[ -z "$CI_COMMIT_TAG" ]] && echo "branch=$CI_COMMIT_REF_NAME" || echo "tag=$CI_COMMIT_TAG")
- insecure=$([ "$CI_SERVER_PROTOCOL" = "http" ] && echo "--insecure" || echo "")
- response=$(curl -s -w "\n%{http_code}" $insecure --data $version $URL)
- code=$(echo "$response" | tail -n 1)
- body=$(echo "$response" | head -n 1)
- if [ $code -eq 201 ]; then
echo "Package created - Code $code - $body";
else
echo "Could not create package - Code $code - $body";
exit 1;
fi
only:
- tags
\ No newline at end of file
#!/bin/bash
# We need to install dependencies only for Docker
[[ ! -e /.dockerenv ]] && exit 0
set -xe
# Install git (the php image doesn't have it) which is required by composer
apt-get update -yqq
apt-get install git -yqq
# Install phpunit, the tool that we will use for testing
curl --location --output /usr/local/bin/phpunit "https://phar.phpunit.de/phpunit.phar"
chmod +x /usr/local/bin/phpunit
\ No newline at end of file
{
"name": "dterumal/laravel-repository-artisan",
"description": "Laravel artisan commands to easily generate interfaces and repositories",
"keywords": [
"dterumal",
"laravel-repository-artisan"
],
"type": "library",
"homepage": "https://gitlab.sib.swiss/dterumal/laravel-repository-pattern",
"license": "MIT",
"authors": [
{
"name": "Dillenn Terumalai",
"email": "dillenn.terumalai@sib.swiss"
}
],
"autoload": {
"psr-4": {
"Dterumal\\RepositoryArtisan\\": "src",
"Dterumal\\RepositoryArtisan\\Tests\\": "tests"
}
},
"extra": {
"laravel": {
"providers": [
"Dterumal\\RepositoryArtisan\\RepositoryArtisanServiceProvider"
]
}
},
"require-dev": {
"orchestra/testbench": "^6.0",
"phpunit/phpunit": "^9.5"
}
}
<?php
namespace Dterumal\RepositoryArtisan\Console;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use InvalidArgumentException;
use Symfony\Component\Console\Input\InputOption;
class InterfaceMakeCommand extends GeneratorCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $name = 'make:interface';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new interface';
/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Interface';
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
$stub = null;
if ($this->option('model')) {
$stub = '/stubs/interface.model.stub';
}
$stub = $stub ?? '/stubs/interface.plain.stub';
return $this->resolveStubPath($stub);
}
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}
/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Contracts';
}
/**
* Build the class with the given name.
*
* Remove the base controller import if we are already in the base namespace.
*
* @param string $name
* @return string
* @throws FileNotFoundException
*/
protected function buildClass($name)
{
$controllerNamespace = $this->getNamespace($name);
$replace = [];
if ($this->option('model')) {
$replace = $this->buildModelReplacements($replace);
}
$replace["use {$controllerNamespace}\Controller;\n"] = '';
return str_replace(
array_keys($replace), array_values($replace), parent::buildClass($name)
);
}
/**
* Build the model replacement values.
*
* @param array $replace
* @return array
*/
protected function buildModelReplacements(array $replace)
{
$modelClass = $this->parseModel($this->option('model'));
if (! class_exists($modelClass)) {
if ($this->confirm("A {$modelClass} model does not exist. Do you want to generate it?", true)) {
$this->call('make:model', ['name' => $modelClass]);
}
}
return array_merge($replace, [
'{{ namespacedModel }}' => $modelClass,
'{{namespacedModel}}' => $modelClass,
'{{ model }}' => class_basename($modelClass),
'{{model}}' => class_basename($modelClass),
'{{ modelVariable }}' => lcfirst(class_basename($modelClass)),
'{{modelVariable}}' => lcfirst(class_basename($modelClass)),
]);
}
/**
* Get the fully-qualified model class name.
*
* @param string $model
* @return string
*
* @throws InvalidArgumentException
*/
protected function parseModel($model)
{
if (preg_match('([^A-Za-z0-9_/\\\\])', $model)) {
throw new InvalidArgumentException('Model name contains invalid characters.');
}
return $this->qualifyModel($model);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['force', null, InputOption::VALUE_NONE, 'Create the interface even if the interface already exists'],
['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate a repository interface for the given model.']
];
}
}
<?php
namespace Dterumal\RepositoryArtisan\Console;
use Illuminate\Console\Command;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Symfony\Component\Console\Input\InputOption;
class RepositoryMakeCommand extends GeneratorCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'make:repository';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new repository class';
/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Repository';
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
$stub = null;
if ($this->option('model')) {
$stub = '/stubs/repository.model.stub';
} elseif ($this->option('interface')) {
$stub = '/stubs/repository.interface.stub';
}
if ($this->option('interface') && ! is_null($stub) && $this->option('model')) {
$stub = str_replace('.stub', '.interface.stub', $stub);
}
$stub = $stub ?? '/stubs/repository.plain.stub';
return $this->resolveStubPath($stub);
}
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}
/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Repositories';
}
/**
* Build the class with the given name.
*
* Remove the base controller import if we are already in the base namespace.
*
* @param string $name
* @return string
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
protected function buildClass($name)
{
$repositoryNamespace = $this->getNamespace($name);
$replace = [];
if ($this->option('model')) {
$replace = $this->buildModelReplacements($replace);
}
if ($this->option('interface')) {
$replace = $this->buildInterfaceReplacements($replace);
}
$replace["use {$repositoryNamespace}\Controller;\n"] = '';
return str_replace(
array_keys($replace), array_values($replace), parent::buildClass($name)
);
}
/**
* Build the model replacement values.
*
* @param array $replace
* @return array
*/
protected function buildInterfaceReplacements(array $replace)
{
$interfaceClass = $this->parseInterface($this->option('interface'));
$modelClass = null;
if ($this->option('model')) {
$modelClass = $this->parseModel($this->option('model'));
}
if (! interface_exists($interfaceClass)) {
if ($this->confirm("A {$interfaceClass} interface does not exist. Do you want to generate it?", true)) {
if ($modelClass) {
$this->call('make:interface', [
'name' => $interfaceClass,
'--model' => $modelClass
]);
} else {
$this->call('make:interface', [
'name' => $interfaceClass
]);
}
}
}
return array_merge($replace, [
'{{ namespacedInterface }}' => $interfaceClass,
'{{namespacedInterface}}' => $interfaceClass,
'{{ interface }}' => class_basename($interfaceClass),
'{{interface}}' => class_basename($interfaceClass)
]);
}
/**
* Build the model replacement values.
*
* @param array $replace
* @return array
*/
protected function buildModelReplacements(array $replace)
{
$modelClass = $this->parseModel($this->option('model'));
if (! class_exists($modelClass)) {
if ($this->confirm("A {$modelClass} model does not exist. Do you want to generate it?", true)) {
$this->call('make:model', ['name' => $modelClass]);
}
}
return array_merge($replace, [
'{{ namespacedModel }}' => $modelClass,
'{{namespacedModel}}' => $modelClass,
'{{ model }}' => class_basename($modelClass),
'{{model}}' => class_basename($modelClass),
'{{ modelVariable }}' => lcfirst(class_basename($modelClass)),
'{{modelVariable}}' => lcfirst(class_basename($modelClass)),
]);
}
/**
* Get the fully-qualified model class name.
*
* @param string $model
* @return string
*
* @throws \InvalidArgumentException
*/
protected function parseModel($model)
{
if (preg_match('([^A-Za-z0-9_/\\\\])', $model)) {
throw new InvalidArgumentException('Model name contains invalid characters.');
}
return $this->qualifyModel($model);
}
/**
* Get the fully-qualified model class name.
*
* @param string $interface
* @return string
*
* @throws \InvalidArgumentException
*/
protected function parseInterface($interface)
{
if (preg_match('([^A-Za-z0-9_/\\\\])', $interface)) {
throw new InvalidArgumentException('Interface name contains invalid characters.');
}
return $this->qualifyInterface($interface);
}
/**
* Qualify the given model class base name.
*
* @param string $interface
* @return string
*/
protected function qualifyInterface(string $interface)
{
$interface = ltrim($interface, '\\/');
$interface = str_replace('/', '\\', $interface);
$rootNamespace = $this->rootNamespace();
if (Str::startsWith($interface, $rootNamespace)) {
return $interface;
}
return is_dir(app_path('Contracts'))
? $rootNamespace.'Contracts\\'.$interface
: $rootNamespace.$interface;
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['force', null, InputOption::VALUE_NONE, 'Create the repository even if the repository already exists.'],
['interface', 'i', InputOption::VALUE_OPTIONAL, 'Generate a repository class which implements the given interface.'],
['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate a repository class for the given model.']
];
}
}
<?php
namespace {{ namespace }};
use {{ namespacedModel }};
use Illuminate\Database\Eloquent\Collection;
interface {{ class }}
{
/**
* Returns a listing of the resource.
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function all(): Collection;
/**
* Store a newly created resource in storage.
*
* @param array $request
* @return \{{ namespacedModel }} ${{ modelVariable }}
*/
public function store(array $request): {{ model }};
/**
* Display the specified resource.
*
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return \{{ namespacedModel }}
*/
public function find({{ model }} ${{ modelVariable }}): {{ model }};
/**
* Update the specified resource in storage.
*
* @param array $request
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return \{{ namespacedModel }}
*/
public function update(array $request, {{ model }} ${{ modelVariable }}): {{ model }};
/**
* Remove the specified resource from storage.
*
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return bool
*/
public function destroy({{ model }} ${{ modelVariable }}): bool;
}
\ No newline at end of file
<?php
namespace {{ namespace }};
interface {{ class }}
{
//
}
\ No newline at end of file
<?php
namespace {{ namespace }};
use {{ namespacedInterface }};
use Illuminate\Database\Eloquent\Collection;
class {{ class }} implements {{ interface }}
{
//
}
\ No newline at end of file
<?php
namespace {{ namespace }};
use {{ namespacedInterface }};
use {{ namespacedModel }};
use Illuminate\Database\Eloquent\Collection;
class {{ class }} implements {{ interface }}
{
/**
* @inheritDoc
*/
public function all(): Collection
{
return {{ model }}::all();
}
/**
* @inheritDoc
*/
public function find({{ model }} ${{ modelVariable }}): {{ model }}
{
return ${{ modelVariable }};
}
/**