Closed eduardoarandah closed 7 years ago
I am sorry I am not following you here with your foreign key naming/comment.
Are you requesting an option that would allow you to have singular naming convention for the controller, table and views' folder? Although this would not be a problem to add it to the config, I like to understand how does it help you with the language variation you stated above? If it is just a preference I completely understand.
Sorry I wasn't clear on the suggestion. A custom pluralize argument would be of great help.
In my case I don't use plurals (because of the irregularities in spanish)
I would love to use something like:
create:resources User --plural=user
"plural" argument overriding str_plural
You can still provide any name convention you like to override the default behavior. please visit the documentation for more info about the available options https://crestapps.com/laravel-code-generator/docs/2.1#how-to-create-resources Keep in mind that the default behavior is intended to save you time and give you very short commands (for English users that is :) )
Try calling the following command to override the naming
php artisan create:resources User --controller-name=UserController --table-name=user --views-directory=user --language-file-name=user
However, I think it is a good idea to allow the user to pass --with-singular-naming
to the create:resources
command to auto convert everything for you without having to explicitly name everything yourself like the the command above suggests. Also I think it is a good idea to add a configuration option to allow you to set this as global setting for all your commands to use singular naming convention so you don't have to pass --with-singular-naming
for each command.
Let me know if the above command, gives you the desired result. Meanwhile, I'll add the above features to the new release when time permits.
Again, thanks a lot for your feedback and your contribution. Suggestions are a great way to improve this package.
Thanks for that!
I'm using your package right now for a real app that has to be completed in record time.
My setup:
Laravel Backpack for the backend because it just works, just configure some crudControllers and the backend is ready in a couple of hours
Crestapps for the front-end Template used: Default-Collective because gives me less code less code=less problems
What I found in the way:
I used https://github.com/InfyOmLabs/laravel-generator but produced too much code
I used https://github.com/appzcoder/crud-generator and is great and simple, but had to copy the command line every time
I loved CrestApps/laravel-code-generator because it saves the model in json and I don't have to use the brain to remember!! great! It also validates inside the controller, so I don't have to generate custom requests for validation (like infyom does)
The hardest part in CrestApps/laravel-code-generator is namespacing and creating sub-folders that match those namespaces. I've solved it by using a bash template
Example: If I'm working in a user profile everything must be prefixed with /home
Bash file is this: This is it:
# vars
prefix=home
entity=profile
layout=layouts.home
# Plurals and Uppercase
fieldsfile=${entity}s.json
model="$(tr '[:lower:]' '[:upper:]' <<< ${entity:0:1})${entity:1}"
namespace="$(tr '[:lower:]' '[:upper:]' <<< ${prefix:0:1})${prefix:1}"
# fields file from BD
pa create:fields-file $entity --table-name=$entity
# Controller
pa create:controller $model --fields-file=$fieldsfile --controller-directory=$namespace --routes-prefix=$prefix --views-directory=$entity
# Views
pa create:views $model --fields-file=$fieldsfile --routes-prefix=$prefix --layout-name=$layout --views-directory=$entity
# Regenerar Form
php artisan create:form-view $model
# Routes
php artisan create:routes $model --routes-prefix=$prefix
@eduardoarandah Thank again for your feedback :)
First of all, I added an option to allow you to create singular named resources from the config. Also, I added an option to allow you to turn off the code-first
approach so no migrations are generated by default.
Try using the last commit in branch v2.2dev
https://github.com/CrestApps/laravel-code-generator/commits/v2.2dev and let me know how it goes :)
Can you please explain the pain point you found in the way with this package to help me improve it?
Cruddiness must be the LAW (read this https://github.com/adamwathan/laracon2017)
What do you wish we do better? Hint: you may want to try generating the resources with a form-request
that will lean up your controllers (i.e. php artisan create:resources Home --with-form-request
)
prefixes and namespaces are VERY important to keep organized
What do you wish we do better here? We already keep everything grouped up in folder to keep your code clean and easy to maintain. Please clearly share your idea to help me understand... A comparison would be great so I can understand your request clearly.
I never auto-generate model/migration because it's just easier by hand
Take advantage of the new use_code_first_approach
option in the config file. Just set it to false
and you won't have to worry about auto-migrations being created.
I always use generator for controller/views
Please explain what is the issue... And what do you like to be different?
The most used: regenerate only the form fields and validations
Please explain what is the issue.... And what do you like to be different?
I don't use plurals because I don't like to use my brain
Like mentioned above, download the latest commit in v2.2dev
and take advantage of the option that allows you to convert the plural resource naming to singular :)
/*
|--------------------------------------------------------------------------
| Plural vs singular naming conventions.
|--------------------------------------------------------------------------
*/
'plural_names_for' => [
'controller-name' => false,
'request-form-name' => false,
'language-file-name' => true,
'resource-file-name' => true,
'table-name' => true,
],
Lastly, why would you need to create a bash file instead of just using the create:resources
command? All the create:resources
does is create all the commands at once.
Thank you
why would you need to create a bash file instead of just using the create:resources command? All the create:resources does is create all the commands at once
What I tried to explain is that your tool is great at the scaffolding phase and beyond
Let's say you have to create a new screen to modify only two fields
well, just create:resources
again (in a sub-folder) and delete all fields except those two
I am sorry I am still confused. You should use create:resources
Command always (when creating and again when modifying) as long as your change is only made to the resources file, the command should recreate everything on its own without the need of any bash file.
@eduardoarandah did you get a chance to try out the v2.2ddev? Did that help you over coming all the challenges you were facing? If needed, here is the documentation for the new version which should be coming up soon. http://crestapps.dev/laravel-code-generator/docs/2.2
Please let me know
Not yet! Too busy right now
By the way, the new laravel 5.5 has some new features that may simplify validation in the controller. Have you seen it ?
Also improves the way the Request grabs null values and non present values
Hey @CrestApps !
I tried it and works perfect
changed this config and generated everything in under a minute, good job!
/*
|--------------------------------------------------------------------------
| Plural vs singular naming conventions.
|--------------------------------------------------------------------------
*/
'plural_names_for' => [
'controller-name' => false,
'request-form-name' => false,
'language-file-name' => false,
'resource-file-name' => false,
'table-name' => false,
],
That's great! Thank you for confirming. Additionally, I changed the default on the controller and the form request name to a singular. Also, not sure what feature are you referring too in 5.5 that would make validation easier.
in 5.5 release notes, says request now has validate method
https://laravel.com/docs/5.5/releases search for text "Request Validation"
But now that I think about it, it wouldn't be a good idea, as it would make it incompatible with previous versions.
I see what your referring too now. As you stated, that will cause issues with versions >= 5.5. But, I will look into making it happen.
However, with the latest commit, you can define custom rules and use them here is more info if you're interested https://crestapps.com/laravel-code-generator/docs/2.2#field-validation
Great!
A couple of things:
In controllers you have a function "data" that converts empty strings to null.
That might be not necessary thanks to this middleware
ConvertEmptyStringsToNull
https://github.com/laravel/laravel/blob/master/app/Http/Kernel.php
And other thing:
What if a malicious user sends a field that must not be present?
You expect to receive in the request name, last name
But receive name, lastname, money, is_admin
Does the controller filter expected fields? Haven't made tests but maybe we need to add something like
$request->only(name,lastname)
Yes I am aware of ConvertEmptyStringsToNull
. I believe that is part of the 5.4 release and won't work for older versions.
Regarding the security concern you brought up, I believe that the fillable fields will protect you as the non-fillable fields will be ignored. I guess, it may not be a bad idea to change $request->all()
to $request->only(['field1','field2'])
.
Would be great!
Because $fillable is a all-or-none solution.
In practice, you want some fields available in certain screens protected by some permission/role
@eduardoarandah I know your going to LOVE this one! For anyone that is using Laravel 5.5+, the generated will have simplified code generated! The code generator will take advantage of the new changes "Request Validation" changes that were introduced with Laravel 5.5. Meanwhile, anyone that is using Laravel 5.1 - 5.4 will still have the same code that we previously generated so it is still a backward compatible.
Event more, anyone that has Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
middlewear registered in Laravel 5.4+ will not see the following code generated any more since the middlewear will do just that :)
$data['...'] = !empty($request->input('...')) ? $request->input('...') : null;
In other words, the Code-Generator will make smart decisions based on the current Laravel version and the loaded resources to determine the best code to generate!
Finally, when generating instead of using $request->all()
, we now generate $request->only([])
as you suggested above :)
If you want to test drive the new changes, make sure you publish the vendor resources as some template and config changes took place.
If your already using dev-v2.2dev
version, you'll have to follow these steps to get the latest code
1) Open composer.json file and update crestapps/laravel-code-generator
version to 2.1.*
2) Execute the following two commands from the command line composer clearcache
then composer update
3) Now, you are back to version 2.1.5
. Now, to get the latest code from the package, Open composer.json
file one more time and update “crestapps/laravel-code-generator
version to dev-v2.2dev
4) From the command-line, execute the following command composer update
which should give you the latest code.
5) publish the latest changed using this command php artisan vendor:publish --provider="CrestApps\CodeGenerator\CodeGeneratorServiceProvider" --tag=default
Note, if you currently using 2.1.*
version, you can just ignore steps 1 and 2. Just follow steps 3 and 4.
Let me know your thoughts on this :)
Here is how the controller looks (Generated Using Laravel 5.4 where ConvertEmptyStringsToNull middlewear is NOT registered)
<?php
namespace App\Http\Controllers;
use App\Models\Test;
use Illuminate\Http\Request;
use App\Models\Manufacturer;
use App\Http\Controllers\Controller;
class TestsController extends Controller
{
/**
* Display a listing of the tests.
*
* @return Illuminate\View\View
*/
public function index()
{
$tests = Test::with('manufacturer')->paginate(25);
return view('tests.index', compact('tests'));
}
/**
* Show the form for creating a new test.
*
* @return Illuminate\View\View
*/
public function create()
{
$manufacturers = Manufacturer::pluck('name','id')->all();
return view('tests.create', compact('manufacturers'));
}
/**
* Store a new test in the storage.
*
* @param Illuminate\Http\Request$request
*
* @return Illuminate\Http\RedirectResponse | Illuminate\Routing\Redirector
*/
public function store(Request $request)
{
try {
$this->affirm($request);
$data = $this->getData($request);
Test::create($data);
return redirect()->route('tests.test.index')
->with('success_message', trans('tests.model_was_added'));
} catch (Exception $exception) {
return back()->withInput()
->withErrors(['unexpected_error' => trans('tests.unexpected_error')]);
}
}
/**
* Display the specified test.
*
* @param int $id
*
* @return Illuminate\View\View
*/
public function show($id)
{
$test = Test::with('manufacturer')->findOrFail($id);
return view('tests.show', compact('test'));
}
/**
* Show the form for editing the specified test.
*
* @param int $id
*
* @return Illuminate\View\View
*/
public function edit($id)
{
$test = Test::findOrFail($id);
$manufacturers = Manufacturer::pluck('name','id')->all();
return view('tests.edit', compact('test','manufacturers'));
}
/**
* Update the specified test in the storage.
*
* @param int $id
* @param Illuminate\Http\Request$request
*
* @return Illuminate\Http\RedirectResponse | Illuminate\Routing\Redirector
*/
public function update($id, Request $request)
{
try {
$this->affirm($request);
$data = $this->getData($request);
$test = Test::findOrFail($id);
$test->update($data);
return redirect()->route('tests.test.index')
->with('success_message', trans('tests.model_was_updated'));
} catch (Exception $exception) {
return back()->withInput()
->withErrors(['unexpected_error' => trans('tests.unexpected_error')]);
}
}
/**
* Remove the specified test from the storage.
*
* @param int $id
*
* @return Illuminate\Http\RedirectResponse | Illuminate\Routing\Redirector
*/
public function destroy($id)
{
try {
$test = Test::findOrFail($id);
$test->delete();
return redirect()->route('tests.test.index')
->with('success_message', trans('tests.model_was_deleted'));
} catch (Exception $exception) {
return back()->withInput()
->withErrors(['unexpected_error' => trans('tests.unexpected_error')]);
}
}
/**
* Validate the given request with the defined rules.
*
* @param Illuminate\Http\Request $request
*
* @return boolean
*/
protected function affirm(Request $request)
{
return $this->validate($request, [
'name' => 'nullable|string|min:0|max:255',
'third' => 'nullable|string|min:0|max:255',
'type' => 'nullable',
'manufacturer_id' => 'nullable',
]);
}
/**
* Get the request's data from the request.
*
* @param Illuminate\Http\Request\Request $request
* @return array
*/
protected function getData(Request $request)
{
$data = $request->only(['name','third','type','manufacturer_id']);
$data['created_at'] = !empty($request->input('created_at')) ? $request->input('created_at') : null;
$data['updated_at'] = !empty($request->input('updated_at')) ? $request->input('updated_at') : null;
$data['name'] = !empty($request->input('name')) ? $request->input('name') : null;
$data['third'] = !empty($request->input('third')) ? $request->input('third') : null;
$data['type'] = !empty($request->input('type')) ? $request->input('type') : null;
$data['manufacturer_id'] = !empty($request->input('manufacturer_id')) ? $request->input('manufacturer_id') : null;
return $data;
}
}
Here is how the controller looks (Generated Using Laravel 5.5 where ConvertEmptyStringsToNull middlewear is registered)
<?php
namespace App\Http\Controllers;
use App\Models\Test;
use Illuminate\Http\Request;
use App\Models\Manufacturer;
use App\Http\Controllers\Controller;
class TestsController extends Controller
{
/**
* Display a listing of the tests.
*
* @return Illuminate\View\View
*/
public function index()
{
$tests = Test::with('manufacturer')->paginate(25);
return view('test.index', compact('tests'));
}
/**
* Show the form for creating a new test.
*
* @return Illuminate\View\View
*/
public function create()
{
$manufacturers = Manufacturer::pluck('name','id')->all();
return view('test.create', compact('manufacturers'));
}
/**
* Store a new test in the storage.
*
* @param Illuminate\Http\Request$request
*
* @return Illuminate\Http\RedirectResponse | Illuminate\Routing\Redirector
*/
public function store(Request $request)
{
try {
$data = $this->getData($request);
Test::create($data);
return redirect()->route('test.test.index')
->with('success_message', trans('tests.model_was_added'));
} catch (Exception $exception) {
return back()->withInput()
->withErrors(['unexpected_error' => trans('tests.unexpected_error')]);
}
}
/**
* Display the specified test.
*
* @param int $id
*
* @return Illuminate\View\View
*/
public function show($id)
{
$test = Test::with('manufacturer')->findOrFail($id);
return view('test.show', compact('test'));
}
/**
* Show the form for editing the specified test.
*
* @param int $id
*
* @return Illuminate\View\View
*/
public function edit($id)
{
$test = Test::findOrFail($id);
$manufacturers = Manufacturer::pluck('name','id')->all();
return view('test.edit', compact('test','manufacturers'));
}
/**
* Update the specified test in the storage.
*
* @param int $id
* @param Illuminate\Http\Request$request
*
* @return Illuminate\Http\RedirectResponse | Illuminate\Routing\Redirector
*/
public function update($id, Request $request)
{
try {
$data = $this->getData($request);
$test = Test::findOrFail($id);
$test->update($data);
return redirect()->route('test.test.index')
->with('success_message', trans('tests.model_was_updated'));
} catch (Exception $exception) {
return back()->withInput()
->withErrors(['unexpected_error' => trans('tests.unexpected_error')]);
}
}
/**
* Remove the specified test from the storage.
*
* @param int $id
*
* @return Illuminate\Http\RedirectResponse | Illuminate\Routing\Redirector
*/
public function destroy($id)
{
try {
$test = Test::findOrFail($id);
$test->delete();
return redirect()->route('test.test.index')
->with('success_message', trans('tests.model_was_deleted'));
} catch (Exception $exception) {
return back()->withInput()
->withErrors(['unexpected_error' => trans('tests.unexpected_error')]);
}
}
/**
* Get the request's data from the request.
*
* @param Illuminate\Http\Request\Request $request
* @return array
*/
protected function getData(Request $request)
{
$data = $request->validate([
'name' => 'nullable|string|min:0|max:255',
'third' => 'nullable|string|min:0|max:255',
'type' => 'nullable',
'manufacturer_id' => 'nullable',
]);
return $data;
}
}
That is great!!
I've used all available generators and yours is clearly the best/easiest!
I'll surely test it man
Best/easiest differently won't settle for less! Hopefully with evenyones input, it will be the most popular code generator package out there to benefit all.
Please let me know your input once you test it
That's the spirit!
In that case I'll give you my feedback in case it helps you.
I've used a lot of platforms/tools Asp, asp.net C#, desktop apps in C#, joomla, drupal, wordpress themes, wordpress plugins, Yii version 1, yii 2, vue and now laravel
The greatest strength in laravel is that it forces you to use advanced tools (composer, git, npm, bash) and advanced programming patterns (single reponsability principle, separation of concerns)
BUT This strength is also its weakness.
You end up with too much code. Too many places for bugs.
Want to change "name" field in your "user" model for a "last name" "first name" ?
you probably have to dig into 60+ files
Want to edit an entity?
you need: route, migration, model, repository, cache logic, a permission, controller, request, views: index, show, edit, delete, form, table
This is where laravel is the weakest. Without a generator, this becomes a pain. too much code.
When coding in Yii2, I used Gii, a generator included in the framework look: http://www.yiiframework.com/doc-2.0/guide-start-gii.html
You may get some amazing ideas from Yii generated code, like
What else may be useful?
Let the community create generators for you.
In my case, I've made templates to use crestapps with AdminLte in laravel-backpack, and will be glad to share.
I'll also would love to create generators for things like: dropzone field select2 vuejs table datatable file upload
I don't know what's the best tool to share knowledge, I've seen this one but never used it https://readme.readme.io
Hope this helps you in some way,
brofist, from Mexico
I hope you seeing that Laravel-Code-Generator, is strengthening that weakness :)
With Laravel-Code-Generator, everything gets store in the resource-file (JSON based) file, so if you want to change the field last_name
to full_name
you can easily do that in the JSON file without touching any code! When you run php artisan create:resources
command, the field will change automatically throughout your code.
I am hoping the community can help by creating different templates for Laravel-code-generator. Unfortunately, I don't have the time to support multiple templates. you can have a datatable based template, a template to submit requests using AJAX....
Lets continue the chat offline. Please find my email in the composer.json file of the packages and send me an email.
Thank you
In latin languages (spanish portuguese italian french romanian) compound words go inverse than english. Example:
in english you say: "User types"
in spanish it is "Tipos de Usuario" maybe valid "Tipos de Usuarios" maybe valid "Tipo de Usuarios"
this becomes a mess!
Imagine the possible foreign keys
Lots of programmers I know, including me, prefer to use all singular, for models, controllers, tables, views, routes, etc
It would be amazing to have that option!