CakePHP Model Name Uses PHP Reserved Word - php

Hey I have coded CakePHP for a number of things but never ran into this problem before surprisingly. Also I have thoroughly searched the net and CakePHP docs and have not found an answer to my question. My question is, I have a table for my model that should be named Class, obviously I cannot use that name though since it's a reserved PHP keyword. What options do I have to be able to refer to this model appropriately.
So far I have;
Renamed my class model file to player_class.php
Renamed my class model class to PlayerClass
Changed var $name to 'PlayerClass'
Added to my class model class; var $useTable = 'classes';
Renamed my class controller to player_classes_controller.php
Renamed my class controller class to PlayerClassesController
Changed var $name to 'PlayerClasses'
While this does work, is this what has to be done or are to other options to be able to refer to it as Class still, like can I do any sort of mangling like _Class?

I once tested all CakePHP class names for Cake 1.2 if they can be used as Model names, here are the results:
NOT possible is:
app
appcontroller
appmodel
behaviorcollection
cache
cacheengine
cakelog
cakesession
classregistry
component
configure
connectionmanager
controller
datasource
debugger
dispatcher
file
fileengine
folder
helper
inflector
model
modelbehavior
object
overloadable
overloadable2
router
security
sessioncomponent
set
string
validation
Possible is:
acl
aclbase
aclbehavior
aclcomponent
aclnode
aclshell
aco
acoaction
admin
ajaxhelper
apcengine
apishell
app_model
apphelper
aro
authcomponent
bake
baker
bakeshell
behavior
cachehelper
cake
cakeschema
cakesocket
consoleshell
containablebehavior
controllertask
cookiecomponent
dbacl
dbaclschema
dbconfigtask
dboadodb
dbodb2
dbofirebird
dbomssql
dbomysql
dbomysqlbase
dbomysqli
dboodbc
dbooracle
dbopostgres
dbosource
dbosqlite
dbosybase
element
emailcomponent
error
errorhandler
extracttask
flay
formhelper
htmlhelper
httpsocket
i18n
i18nmodel
i18nschema
i18nshell
iniacl
javascripthelper
jshelper
jshelperobject
l10n
layout
magicdb
magicfileresource
mediaview
memcacheengine
modeltask
multibyte
numberhelper
page
pagescontroller
paginatorhelper
permission
plugintask
projecttask
requesthandlercomponent
rsshelper
sanitize
scaffold
schema
schemashell
securitycomponent
sessionhelper
sessionsschema
shell
shelldispatcher
test
testsuiteshell
testtask
texthelper
themeview
timehelper
translate
translatebehavior
treebehavior
viewtask
xcacheengine
xml
xmlelement
xmlhelper
xmlmanager
xmlnode
xmltextnode

When i run into this sort of problem i usually do what you did, only i prefix the reserved word with "My" (so when i read the code it doesn't look like that class has anything to do with "Player"... for example, just the other day i wanted to model a "ACO" model.. but that already existed in cake (same scenario of reserved word) so i created a model called Myaco.
I think you should just name it Myclass.
Regarding the model name and controller name changes- i think you did good, i would do the same. Your only real option is to use the $useTable = 'classed'; to use your DB table.
If you use the underscore prefix, i believe cake will not be able to handle it (it will fail in the Inflector class).
Good luck

I can second that solution. I had the same problem and used a prefix that was the initials of the client. Ended up calling mine Dtclass. Unfortunately, it took me an hour or so to figure out what the problem was. One of those cases where the answer stares you in the face all the time till you finally recognize it.

Related

Need an advise with controller/model naming

At this moment i am having a problem, my controller called userspace, his model called userspace and view is userspace too, logically everything is fine, but just a plain example when you open this 3 files sometimes it's hard to understand where is model and where is controller if not to start reading the code.
So i ask for advises or examples of coding standarts :)
I normally tend to use singular/plural to distinguish from model/controller.
That being said, this is how I do things:
Model
File name: app/classes/model/userspace.php
Class name: Model_Userspace
This is also FuelPHP's naming convention (at least for Models). This way you don't have to specify the table name on the model, like so:
protected static $_table_name = 'userspaces';
because FuelPHP will look for the plural version of your model name.
Controller
File name: app/classes/controller/userspaces.php
Class name: Controller_Userspaces
Views
Folder: app/views/userspaces/
This keeps things organized per controller name. For each controller action, a view should be created. So, if you have a create and edit action in your Controller_Userspaces, you will create the following files:
Create: app/views/userspaces/create.php
Edit: app/views/userspaces/edit.php
Forging the views should be a matter of calling:
View::forge('userspaces/create');
View::forge('userspaces/edit');
You should check the FuelPHP ORM documentation for more information.
UserSpaceView(view/gui) / UseSpaceViewController(controller) / UserSpaceModel(model)
We namespace everything, instead of using underscores, so
\Controller\Userspace
\Model\Userspace
\View\Userspace
and
\Module\Controller\Userspace
\Module\Model\Userspace
\Module\View\Userspace
For models you can do directly, for controllers you need to change the controller prefix in the config (from "Controller_" to "Controller\"), which means you have to namespace ALL your controllers from this point.
This is going to be the standard for Fuel v2, it will not support "underscore to directory separator" mapping anymore.
Note that \View maps to ./classes/view, which are Viewmodel classes, not View files!

using model class name "Class" in cakephp

I have table name "classes" in database and when i create model with name "Class" ,it gives syntax error (obviously).Is there any way to remove this error without changing name of table in database ?
I would stay away from a model named "Class", it is a keyword of php and it may will (as pointed by #AD7six) cause trouble if instantiated like that.
You can do the following:
class MyClass extends AppModel {
public $useTable = 'classes';
}
Be sure that the controller ClassesController calls MyClass (with $uses), but besides that, you can use the model like any other model without worrying about reserved keywords.
I can't remember the name I used but I had a similar issue with cakephp and after some looking online it worked out to be so much easier to just change the table name. The naming conventions are quite strict and creating a work-around for this isn't worth it.
You could find a different name for your model and then link that model to your table using useTable
hope that helps

Strategies for cleanly extending Propel Models in Symfony2?

I want to do this:
// Model class
namespace Bookshop\Inventory\Model;
use Core\Inventory\Model\Product as BaseProduct;
class Book extends BaseProduct {
// ...
}
// Query class
namespace Bookshop\Inventory\Model;
use Core\Inventory\Model\ProductQuery as BaseProductQuery;
class BookQuery extends BaseProductQuery {
// ...
}
Looks fine, right? But:
$book = BookQuery::create()->find($id);
var_dump(get_class($book));
// expected: Bookshop\Inventory\Model\Book
// actual: Core\Inventory\Model\Product
AFAIK this is due to the fact that Propel's relationships are defined at build-time, not runtime... The only way I have found of achieving this is by using the extend behaviour found in the GlorpenPropelBundle and defining the extended classes in my config:
glorpen_propel:
extended_models:
Core\Inventory\Model\Product: Bookshop\Inventory\Model\Book
Fine, it works, but surely there's a better way? Have I missed something, or is this really the only way to extend Models in Propel + Symfony? I really want to use Propel over Doctrine, but things like this leave me thinking that Propel simply isn't suited for projects over a certain size...
(Propel 1.6 + Symfony 2.3 btw)
I'm the creator of GlorpenPropelBundle so i thought i could shed some light on issue :)
Propel does provide model classes for modification but sadly when talking about external Bundle's with their own model that classes are generated inside them. There is no second-level user classes.
In some cases you can however make use of Propel single inheritance behavior - http://propelorm.org/documentation/09-inheritance.html or solution provided by hakre .
If you want to simply add some methods to vendor bundle model, you are out of luck.
In olden times there was http://trac.symfony-project.org/wiki/HowToExtendPropelPluginModel but now there are some cases it will not work - and that is where my bundle goes into action.
If you are inside own application, you can always do class extending in following way (since Propel user classes are generated only once):
namespace Bookshop\Inventory\Model;
//your custom class extending Propel base class
class Book extends \Core\Inventory\Model\om\BaseProduct { ... }
namespace Core\Inventory\Model;
//propel user class extending your custom class
class Book extends Bookshop\Inventory\Model\Book {...}
The issue you have and ask about is as you already wrote about built-time / runtime. As BookQuery::create() is a static method it resolves the model classname to BaseProduct.
This is as well outlined in the Propel manual:
Due to late static binding issues in PHP 5.2, you cannot use the create() factory on an inherited query - unless you override it yourself in the descendant class. Alternatively, Propel offers a global query factory named PropelQuery:
<?php
// Use 'frontendBook' instead of 'Book' in the frontend to retrieve only
// published articles
$books = PropelQuery::from('frontendBook')->find();
Source: Propel Query ReferenceDOCS - scroll down to the very end.
So either override it or specify it.
I hope this solves your issue as it allows you to specify which query and therefore entity class to be used by propel.
The Glorpen Propel Bundle takes a different route by the way, changing the code that is being executed for the static getOMClass method. This smells like a hack in my nose, but it's too early that I judge. You find the code in Behaviors/ExtendBehavior.php.

Php class declaration inside class method with same names and PSR-0 namespaces, error

I have create my own MVC framework which is PSR-0 compliant atm. and uses php-ActiveRecord as ORM.
I have found an issue where I from a controller called User, which exists in the namespace TapMVC\Application, tries to call an ActiveRecord model ALSO called User but exists in the namespace TapMVC\Db like so:
namespace TapMVC\Application;
use TapMVC\Db;
class User extends Controller {
function index() {
print_r(Db\User::find('all'));
}
}
This gives the following error:
Cannot redeclare class TapMVC\Application\User in
/path/to/project/app/Controllers/user.php on line 12
Where line 12 is the prototype/declaration of the User-controller.
Why can't i do this? I thought that if your classes where i different namespaces and had a namespace prefix on instantiation it would be ok to have the same name? Also it looks like the data-model is declared before the controller through autoloading (since its the user-controller declaration which triggers the error), so why is there a conflict when the data-model is in namespace TapMVC\Db and not TapMVC\Application where the controllers are?
What i can see, that even though you define different namespaces, PHP will declare the object under the same namespace as the one in the active file, but i am not sure.
Hope someone can help so i dont need to name my data models like so: (ProjectName-prefix)User and edit the database tables in order to have a User-model and a User-controller.
I found the error! :-D
The issue lied in my autoloading functions for controllers, models etc. since i didn't take care of namespaces. So when I tried to load a controller or model named the same, the spl_autoload_register function would start off by checking for controllers, and since my functions ignored the classes namespaces it would i both cases of: TapMVC\Application\User and TapMVC\Db\User find the User-controller class, stop the autoload list, and try to declare it.
This all resolved when i took care of the namespaces and made sure that controllers/models only get loaded as long as they are in the correct namespace. If not the function dose nothing and the spl_autoload_register function continues down the list of autoload functions.
The question was more framework specific than imagined and boiled down to autoloading which i didn't think was the problem... for some reason, and for that i am sorry. Just happy know that I found the error.

PHP workaround to extend classes of the same name?

I know extending a class with the same name is not possible, but I was curious if anyone knew of a way to load a class then rename it, so i can later extend it with the original name. Hopefully like something below:
<?php
//function to load and rename Class1 to Class2: does something like this exist?
load_and_rename_class('Class1', 'Class2');
//now i can extend the renamed class and use the original name:
class Class1 extends Class2{
}
?>
EDIT:
Well, I understand that this would be terrible practice in a basic OOP environment where there are large libraries of class files. But i'm using the CakePHP MVC framework and it would make great sense to be able to extend plugin classes in this way since the framework follows a well established naming convention (Model names, view names, controller names, url routes (http://site.com/users), etc).
As of now, to extend a CakePHP plugin (eg: Users plugin) you have to extend all the model, view, and controller classes each with different names by adding a prefix (like AppUsers) then do some more coding to rename the variable names, then you have to code the renamed url routes, etc. etc. to ultimately get back to a 'Users' name convention.
Since the MVC framework code is well organized it would easily make sense in the code if something like the above is able to be implemented.
I'm trying to work out why this would be necessary. I can only think of the following example:
In a context that you have no control over, an object is initialised:
// A class you can't change
class ImmutableClass {
private function __construct() {
$this->myObject = new AnotherImmutableClass();
}
}
$immutable = new ImmutableClass();
// And now you want to call a custom, currently non existing method on myObject
// Because for some reason you need the context that this instance provides
$immutable->myObject->yourCustomMethod();
And so now you want to add methods to AnotherImmutableClass without editing either Immutable class.
This is absolutely impossible.
All you can do from that context is to wrap that object in a decorator, or run a helper function, passing the object.
// Helper function
doSomethingToMyObject($immutable->myObject);
// Or decorator method
$myDecoratedObject = new objectDecorator($immutable->myObject);
$myDecoratedObject->doSomethingToMyObject();
Sorry if I got the wrong end of the stick.
For more information on decorators see this question:
how to implement a decorator in PHP?.
I happen to understand why you would want to do this, and have come up with a way to accomplish what the end goal is. For everyone else, this is an example of what the author may be dealing with...
Through out a CakePHP application you may have references to helper classes (as an example > $this->Form->input();)
Then at some point you may want to add something to that input() function, but still use the Form class name, because it is through out your application. At the same time though you don't want to rewrite the entire Form class, and instead just update small pieces of it. So given that requirement, the way to accomplish it is this...
You do have to copy the existing class out of the Cake core, but you do NOT make any changes to it, and then when ever you upgrade cake you simply make an exact copy to this new directory. (For example copy lib/Cake/View/Helper/FormHelper.php to app/View/Helper/CakeFormHelper.php)
You can then add a new file called app/View/Helper/FormHelper.php and have that FormHelper extend CakeFormHelper, ie.
App::uses('CakeFormHelper', 'View/Helper');
FormHelper extends CakeFormHelper {
// over write the individual pieces of the class here
}

Categories