Avoiding _model suffixes in CodeIgniter - php

If you're like me, you think CodeIgniter is pretty nice. You also probably hate typing _model every time you load or call a method or property from your models, because it's ugly and time-consuming.
I've been searching for a solution to this for a couple hours with no luck - so I put together a quick fix.

Take a look at the loader class documentation.
Say you've got a class called page_model, you would typically load and use it like this:
$this->load->model('page_model');
$this->page_model->function();`
If you want to avoid typing _model every time you can do this:
$this->load->model('page_model', 'page');
$this->page->function();
When I first started using CodeIgniter I always did this. Now after using CI for several years and a number of websites, I regret that decision.
It's harder to tell what's going on when looking at the code. Having the _model as part of the code that calls the model function removes any ambiguity. For example, in the above function call is page a library or a model?

This is because CodeIgniter does not support namespaces. While there have been discussions of namespace support in CI for some time, support in the stock codebase is still forthcoming.
The solution? Prefix your controllers instead! In typical usage, you're unlikely to need to type the name of the controller more than once per file.
First edit application/config/routes and add the following line after all the other routes:
$route['(:any)'] = "c_$1";
With this rule, you route the first segment of the URI to the matching controller with your prefix. So that:
http://www.domain.com/fishsticks
maps to the following controller:
c_fishsticks
Next, rename your controller files with this prefix, as well as altering the class names inside to match.
That's it! Now you can name your models with relative freedom. You can rename your models at your leisure, but don't forget that you need to change each model's filename, each model's class name, as well as all references to each model. This is easily the most time-consuming step, but on the plus side you don't have to do it all at once.

Related

Yii2: a proper way to resolve ambiguity of controller and module names

As far as I know, currently Yii 2 doesn't have an out of the box method to resolve ambiguity of controller and module names. An example of module hierarchy to describe what exactly I mean:
app\modules\v1\controllers\UserController // resolves the /v1/users and /v1/users/{id} actions
app\modules\v1\modules\user\Module.php // nested module, resolves the /v1/user/... controllers and their actions, e.g. /v1/user/something/{id}
In this case, the UserController conflicts with the user Module. The main reason of the ambiguity is the singular-plural magic of Yii 2 framework. I didn't find an appropriate solution to resolve this ambiguity. Further my ideas how to resolve it.
Rename the module.
Rename the UserController to the UsersController.
Create an additional submodule, and place there the UserController. E.g. app\modules\v1\modules\root\controllers\UserController
I'm not sure that at least one of these options is a quite elegant one and a proper solution in view of the Yii 2 philosophy.
Coming back to the main question, what is a more appropriate approach to resolve this issue by the Yii 2 philosophy? Controller and Module is two different types of objects, which is differently pluralized or not, thus should be right way to separate them in the routing for the described case.
How I usually deal with this depends a bit on how I'm structuring things.
Let's say I have users, departments, orders and maybe some other stuff. All these concepts have their own module in which all interactions take place. If I want to create REST controllers for all these concepts I can choose to add a controller to every module or I can create a dedicated API module for the controllers.
When creating a dedicated module for this purpose I usually name it api, maybe with some nested versioning module(s) inside. So in this situation I would get the following structure app\modules\api\controllers\UserController which would result in the URL /api/user. No ambiguity there and pretty clear what this is meant for.
When adding such a controller to the module itself I choose a better name than just 'UserController'. When asking myself the question 'What does this controller accomplish?/What does it do?' I find that just UserController doesn't cut it; Especially when inside a User module, resulting in /user/user. This controller is probably going to exist alongside one or more different controllers in the User module, all meant for something different. So, usually, I end up naming it just ApiController, resulting in /user/api. Another controller could be the ProfileController. So when looking at the URLs it's pretty clear what /user/api and /user/profile do. Without the ambiguity.
I am not sure I can fully understand the question, but probably you're asking about classname aliases?
use My\Full\Classname as Another;

What's the reason behind using routes file in modern frameworks?

In modern web frameworks (Laravel, Symfony, Silex, to name a few), there seems to be a pattern of using a routes.php file or similar to attach URIs to controllers. Laravel makes it a bit easier with an option to use PHP annotations.
But to me all this feels like a bit of a code repetition, and when you are creating/modifying controller logic, you have to keep routes file always at hand. Interestingly, there's a simpler way I saw in several old frameworks, and I used to use this in my old projects as well:
Controller. All classes in src/controllers folder (old way) or all classes in YourApp\Controllers namespace are being automatically mapped to the first part of the URL by adding "Controller" to it. Example: /auth gets mapped to AuthController, /product/... — to ProductController, and / — to default IndexController.
Action. Action is the second part of the URL, and it gets mapped to the method name. So, /auth/login will call AuthController::loginAction() method. If no second part provided, we try indexAction(). Don't want people to access some internal method? Don't make it public.
Parameters. Next parts of the URL are being mapped to the arguments of the method; if there are Application and/or Request type hintings in the argument list, they are skipped so they can be properly injected; we can access GET/POST variables as usual through Request.
Here's the full example, using all these features together:
URL: https://example.com/shop/category/computers?country=US&sort=brand
namespace MyApp\Controllers;
class ShopController extends BaseController {
public function categoryAction(Application $app, Request $req, $category, $subcategory = null) {
echo $category; // computers
echo $subcategory; // null, it's optional here
echo $req->get('country'); // US
echo $req->get('sort'); // brand
}
}
I'm sure it seems to lack some familiar features at first, but all features that I can think of could be easily added if needed — using attachable providers, connecting middlewares, branching controllers to subcontrollers, specifying HTTP methods, and even performing a bit of a pre-validation on the arguments. It's very flexible.
This approach would really speed up the routing creation and management. So besides having all the routes in one file (which is also not always true, considering various providers, using ->mount() in Silex or bundles in Symfony), what are the reasons modern frameworks seem to prefer this way of doing MVC routing over the simpler way I've described? What am I missing?
I'll speak here from Symfony/Silex perspective:
Decoupling. routes.php provide separation of URL mapping and controllers. Do you need to add or change URL? You go straight to routes.php. Very handy if you want to change a lot of them.
Flexibility. Generally, routes.php is a bit more flexible approach. SEO might go crazy and might require you to have route like /shop_{shopName}/{categoryName}/someStaticKeyword/{anotherVar}. With routes.php you can easily map this to your code, but this might become a problem if your routes are directly mapped to the code. Even more, you can have this only controller, you don't need to write controllers for each slash part. You can even have different controllers handling the same URL with different variable parts, for example /blog/[\d]+ or /blog/[a-z-]+ being handled by different controllers (one might generate redirect to another). You might never need to do something like this, but this is just a demonstration of flexibility of this approach - with it anything is possible.
Validation. Another thing to consider is that routes.php provide simple means of validation via ->assert method. That is, routes.php does not only map URLs to controller methods, but also ensure that these URLs match specific requirements, and you don't have to do this in code (which in most scenarios would take a bit more code to write). Also, you can create default asserts for some variables, for instance, you may ensure that {page} or {userId} are always \d+, single line in routes.php that would take care of all usages of {page} or {userId}.
URL Generation. One more feature of routes.php is url generation. You can assign any route any name (via ->bind() method) and then generate URLs based on that name, and providing variables for parts of URL that change. And once we have this system and use URL generator throughout our code we can change URLs as much as we want, but we won't have any need to edit anything but routes.php. And once again - these are flexible names, that you won't have to change everywhere throughout your project once URL has changed and you are not limited choosing the name. It might be much shorter than the URL, or a bit more verbose.
Maintainability. Say, you might want to change some urls (as in example above - from /blog/[\d+] to /blog/[a-z-]+. Also, you might want to keep both of them for some time, and make old one redirect to the new one). With routes.php you simply add a new line and add a todo memo to remove it in some time if you want to remove it later.
Sure, all of this might be achieved with any aproach. But would that be this simple, flexible, transparent and compact as this approach?
Just as note, the standard edition of Symfony is shipped with SensioFrameworkExtraBundle, that allows to use annotations instead of file-based declaration:
/**
* #Route("/")
*/
public function indexAction()
{
// ...
}
In the same manner, you can set the prefix for the whole controller file:
/**
* #Route("/blog")
*/
class PostController extends Controller
{
/**
* #Route("/{id}")
*/
public function showAction($id)
{
}
}
Still, we have to declare it. I think the main reason is that routing requirements are heavily influenced by SEO optimizations. For anything that faces the public you want some keyword-rich URL. The "public" logic organization may also be different, you may have only one controller to deliver all your static pages, still you want those to be /contact, /about...
In some domains, routes can be inferred with conventions. If you create a REST API using FosRestBundle, it will auto-generate routes based on your controllers/actions names on the ressource approach. In general I think the FosRestBundle got a lot of things in their approach, you can easily parse and validate query parameters at the same time:
class FooController extends Controller
{
/**
* This action route will be /foo/articles, GET method only
*
* #QueryParam(name="val", default="75 %%")
*/
public function getArticlesAction(ParamFetcher $paramFetcher)
{
...
}
I always prefer having the routes in a config file rather than using annotations because, firstly, I feel it's more maintainable and easier to have an oversight. It's easier to ensure that you don't have any conflicting routes when you can see them all together.
Additionally, it's theoretically faster. Annotations require reflection, where the application needs to scan the file system and parse each controller to collect the set of routes.
The reason is probably maintainability for the long term. It doesn't matter how the routes are set up but generally, Laravel as a framework focuses on the simplicity and the small things that make the framework great. As long as it is easy to use for the user (web developer in this case), the goal is reached.
You can use a different name for the routes.php file and also use multiple route files, if you have a lot of routes in your application.
You can try and rethink the whole concept to improve it but I don't think that Laravel's routes need really a big change to make it even easier. It's already simple. Maybe it will be changed for the better in the future but for now, I think it's fine.

Method navigation/Usage finding in Laravel projects with NetBeans

I often use Ctrl+Click on a method to navigate to its declaration, or RClick -> Find Usages to see all usages of it.
In Laravel you often define in strings which method shall be called. For instance:
Route::get('customer/{id}', 'CustomerController#customer');
I see no way to navigate to the method customer in the class CustomerController automatically here. Find Usages doesn't find this one either.
Is there any way to get it working?
As you said in your question, CustomController#customer is a string. So you cannot click on this string to find out its usages.
However, you can still create a route name for your routes and check for those routes. You can use this route names in your controllers, views and even models.
So using route names would give you tremendous flexibility in development. Just change your method usage in routes.php and it will be reflected in all places.

Controllers naming convention in Laravel 5

All controllers in Laravel 5 are still named with Controller suffix, like AuthController and PasswordController. Is there any reason to follow this convention with own controllers, or are those suffixes just leftovers from pre-namespacing era?
I use action-based URL generation most of the time, so I avoid linking like url('home'), but prefer something like action('HomeController#index) instead. This way I can change URL patterns without a headache.
But action('Home#index') is so much more elegant. Any traps behind it?
There's no need to add the Controller suffix. If it was really needed, when you create a Controller through artisan, it would automatically add it, or complain about it, and it is not. So, feel free (but keep in mind that if you want a controller "Dog" and there is a model "Dog"... well, it will be complicated).
No need of adding Controller Suffix. It is just user recognition. So that we can easily get that is an controller. You can normally create Home instead of HomeController. And action('Home#index') will perfectly work. But models in Laravel is something different. If your model name is in singular your table name will be plural. And this is also not a compulsory thing. But if we add Controller in suffix it would be best in using controller and model. Because we will add use home and use app\home in the controller. This would confuse us.
Having Controller at the end of every controller class name does feel like a type of Hungarian notation. However, a class's name should tell the programmer quickly and unambiguously what it does. A DogController is not a Dog. In fact, I can't think of a better name than DogController for it.
Yes, it is namespaced as App\Http\Controllers\DogController which seems like double handling, but how often do you think about or refer to a class by its fully qualified name? Most often a class is referred to just by its class name, and PHP even allows you to do this in code with use App\Http\Controllers\DogController; which will make DogController a valid class name in your code.
That being said, Laravel will not force you to use this convention. If you are working with other programmers you need to have an agreed naming convention, and using Laravel's is the easiest as well as the one most Laravel programmers will already be familiar with.

CakePHP creating a component or another controller

I have a very big AppController. Nearly 75 functions and 130 kilobytes. It seems like that slows my system. Therefore I need to put those functions inside another file, and include that file, when some other controller needs it.
Options are creating a new controller or a new component. I'm trying to make a selection. What would be the advantages or disadvantages?
My points are:
I don't plan to use these functions inside another project. These functions will only be used by this project.
Inside my AppController I use these files, models, components. So they should be accessible by new structure.
App::import('Vendor', 'MyFancyVendor', array('file' => 'MyFancyVendor.php'));
App::uses('CakeEmail', 'Network/Email');
public $uses = array('Mytable1', 'Mytable2', 'Mytable3', 'Mytable4');
public $components = array('Session');
public $helpers = array('Session','Html');
Edit: Although using a huge new controller/component seems like the same with the old structure, difference is: Say it MyController12 and MyController13 doesn't use the methods of these huge functions inside AppController. But because of MyController12 is created from AppController it loads models, components and other things that it doesn't need. If I put of these logic out of my AppController, MyController12 will not load all that logic.
Follow this pattern:
Gather all related functionality in libraries.
Move all the data logic in the models.
Move all the view logic int the views (remember views are not templates)
For whatever else left, create some helpers
This will make your controller thinner. Creating other controllers should be your last chance, considering that you really don't want to use these kind of functionality in any other projects or part of the website.
The number of functions and the size of the files has absolutely no impact on the time code takes to execute.
Example: this has over 50 plugins loaded, 100ish controllers, 84k lines of code and the pages load reasonably fast.
You need to look at the queries being run. I suspect you are using queries with recursive set to 1 or 2. You should use containable at the very least.
Also look at the explain for your selects. If you are using mysql check that, or what ever is similar for your engine.
You can also install debug kit which displays a lot about what is taking time and can be sped up.
From what i can read, maybe its best that you think about dividing your AppController into multiple different files. Without seeing what your AppController it seems like it is assuming a lot of different roles.
Maybe its better to use different controllers for Mytable1, MyTable2, Mytable3, Mytable4, and use Components to share any information between them.
To answer your question, it is to use BOTH, and also to use Libs, and Helpers. Controllers where necessary, and Components where necessary. There's no point in changing your huge AppController into a huge Component. Split your files where you see something in common. Such as a ImageController, or Postcontroller, both however will use the Session Component.
Edit: What about changing the $helpers, $components, and $uses, from the AppController to the Individual controllers? Use relationships so that CakePHP can find the models. And make sure controllers aren't loading extra models / classes, as i doubt a big controller would cause sluggishness ( unless its your code )

Categories