I am using cakephp 2.6.9. I have a table named: chat_info and model file: ChatInfo.php and class inside ChatInfo:
<?php
/**
*
*/
class ChatInfo extends AppModel
{
var $name = "chatinfo";
}
?>
but it shows an error. I searched for this error and found that this is due to naming convention violation in cakecaphp. But whats wrong am I doing here
Model::useTable
As found in the docs:
The useTable property specifies the database table name. By default, the model uses the lowercase, plural form of the model’s class name
Conventions are not intended to be unbreakable rules. They are guidelines which, if followed, make life easier. That does not mean they have to be followed. Using useTable it's possible to use any table name, in this case:
class ChatInfo extends AppModel
{
public $useTable = "chat_info";
}
Two asides, assuming you're not actually using php4:
It is a terrible idea to set the model name to something other than the actual model name. It's not necessary to set it to anything, since it's designed purpose is php4 compatibility. The name of a model is the class name, setting it to something else can easily lead to confusion or unexpected side effects.
Declaring variables with var is php 4 style, use the features of the version of php in use, i.e. declare variables using public, protected or private.
if you will rename the table from chat_info to chat_infos it will be ok
Or if you want to mantain that name for the table then add this in your model:
$useTable = 'chat_info';
and your model will be associated to the table chat_info (without plural mode)
Related
(I come from Visual Studio + Entity Framework background and trying to locate equivalent functionality in Laravel + Eloquent)
In EF and Visual Studio, we add a new Model to our application and just tell it about our existing database. EF can then generate Models for my tables with public properties for columns. This gives us all those IDE and compiler benefits such as Intellisense, spelling-error detection etc.
I've recently stated exploring VS Code, Laravel and Eloquent. Going through all those tutorials and articles, I'm not sure when and how these properties are generated in the model classes. I just tried artisan make:model command and it did generate the model class, but there are no properties in it. So,
Am I supposed to write them by hand? (really?)
Will these just be public variables or standard properties with getter/setter (excuse me for my .NET mentality :))?
Is there a tool/extension that could examine my database and create models with properties for their columns?
Update
To the people who answered my question, thanks a lot. Plus some of the comments I posted were due to my ignorance about PHP's (strange IMO) approach about member access; I just found out that PHP does not complain about non-existing class members and instead generates them on the fly (e.g. $post->NonExistingMember = SomeValue runs okay; this would not even compile in most other languages that I know). Big surprise for me. I have used C++, VB, C#, Java among several other languages and haven't seen that behavior anywhere else. All those languages would throw a compile-time error straight away saying something like Type X does not contain a member named Y. Cannot see how PHP's different approach fits together with OOP.
The actual problem that I posted this question for still remains unresolved. Although I can use reliese/laravel to generate Model classes for my database, the tool still does not generate class members against table columns, so I do not get auto-complete benefits. I'd love to hear from the experts if that can be done (automatically of course).
Update 2
Now that I understand Laravel environment slightly better, I thought I'd share my experience. See my answer below.
Now that I have spent some time with Laravel, Eloquent and PHP in general, I'll share a few things in the hope that these helps other starters.
PHP is a dynamic language and its code is compiled on the fly (this is unlike C# and VB.NET). Your model classes do not need to explicitly define members for them to be accessible/assignable, so as long they extend Model (a built-in class in Laravel Eloquent), you can assign values to non-existing members that have the same name as the underlying database table column and Eloquent will store it in the DB for you. So for example, if you have a posts table in your database that has a column named body, you can write the following code to create a new record in your database:
$p = new Post;
$p->body = 'Some stuff';
$p->save();
Of course you need to have a class Post in your project that extends from Model but you don't need to define a member body inside that class. This would sound strange to the people coming from .NET world, but that's how dynamic languages work.
As for automatically generating models, Laravel includes built-in commands (php artisan make:model) that can generate those for you.
Lastly, for intellisense and auto-complete, use the same tool that is used by Laravel itself, i.e. DocBlocks. These are special type of comments in PHP using which you can document your code elements. So you can add DocBlocks to all your model classes containing property names and types. Fortunately for everyone, there is a very neat extension in VS Code that can do this automatically for you. Install it using the following command:
composer require --dev barryvdh/laravel-ide-helper
Now run the following command to generate DocBlocks for all of your model classes (obviously you should already have generated your database and models before this):
php artisan ide-helper:models --dir='app'
The extension will fetch the structure of your database and inject DocBlocks to all your models, which will look something like this:
/**
* App\User
*
* #property int $id
* #property string $name
* #property \Illuminate\Support\Carbon|null $created_at
* #property \Illuminate\Support\Carbon|null $updated_at
* #method static \Illuminate\Database\Eloquent\Builder|\App\User whereCreatedAt($value)
* #method static \Illuminate\Database\Eloquent\Builder|\App\User whereId($value)
* #method static \Illuminate\Database\Eloquent\Builder|\App\User whereName($value)
* #method static \Illuminate\Database\Eloquent\Builder|\App\Exam whereUpdatedAt($value)
* #mixin \Eloquent
*/
class User extends Model
{
}
VS Code will now show you table field names in model properties, like this (see how intellisense brings up name member from our DocBlocks as we type na...):
Note that I also have Intelephense installed in my VS Code, though I'm not sure if that is required for auto-complete feature to work.
Edit
Dynamic Properties have been deprecated in PHP 8.2 and I'm hearing that they'll become invalid in PHP 9.0, which means Laravel models should not be able to do this magic stuff in the future versions.
I'm not a PHP guru, but I hear that we don't need to panic. Two things: Firstly, the objects implementing __get and __set will keep working fine. Secondly, Plus you (they) can also use #[AllowDynamicProperties] on model classes to allow dynamic props. And lastly, they can rewrite model generator to spit out column names as props in the model class. This last one will be the best and will take PHP one step closer to how C# world works (precisely where this post started, lol).
I use annotations to declare all the properties for autocomplete (works in PHPStorm, not sure about other IDEs).
/**
* #property $id
* #property $microsoft_id
* #property $name
* #property $qualification
* #property $company
*/
class ShopTenant extends Model
{
public $connection = 'shop';
public $table = 'tenants';
protected $guarded = ['id'];
}
You can use something like this to get a list of all columns of a table, then paste/format that list into your annotations:
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'tenants';
Unfortunatilly yes, you need to write them by hand, but only if you need to update the value of these properties, check point 2($fillable array)
You need to declare the properties that can be filled:
For example a model called Post for a database table "posts" that has 2 columns "title" and "body" :
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
//not mandatory to declare the table name, Laravel will find it using reflection if you follow the naming standard
protected $table = 'posts'; //not mandatory
protected $fillable = ['title','body'];
}
In the controller:
$newPost = new Post;
$newPost->title = 'A new title';
$newPost->body = 'A new body';
$newPost->save(); //only at this point the db is modified
Or you can hide them if you return the properties in an array or a JSON response(in the Collection also the hidden ones will be displayed):
protected $hidden = [
'title',
];
Also you can inject new properties in the model using Accessors
I don't think so, you can install some Laravel VS Code plugins to make your life easier(e.g: Blade snippets)
You can check this article.
Actually you don't need to specify the properties. Its all done by laravel automatically. When you create a model laravel uses the plural (and it has a really good system for that: post becomes posts, activity becomes activities, etc.) of the classname to access the table. So you can work with an empty model without setting the $table or the $fillable/$guarded property.
// use only, if your table name differs from the models classname
$table = 'users_options'; // when you want to name your model 'Vote' but the table is called 'users_options' for instance.
// use fillable and guarded only to specify mass-assignment columns
$fillable = [whatever, ...];
$guarded = [whatever, ...];
you can access the properties whenever you want:
class Post extends Model
{
}
// would do sth like this: select name from posts where id = 1;
// without specifying anything in the model
$name = Post::find(1)->name;
You need to add by yourself. for example
$fillable = ['firstname', 'email','username'];
$guarded = ['price'];
I am currently working on a web app that has been set up using the Repository/Service Layer Design Pattern, i.e. I have service layer that does any necessary business logic before running any methods within the repository. I have facades for each one of my models which access their respective service layers, and this has been fine for the most part. However, now that I am trying to set up Eloquent relationships, the facades seem to be causing a massive headache as I am not sure which direction I should be going.
Take the following code:
class Account extends Eloquent {
// Our table name
protected $table = "accounts";
// Our primary key
protected $primaryKey = "id";
/**
* Role Relationship
*
* Returns a list of roles associated with
* this account
*/
public function roles() {
return $this->hasMany('Role');
}
}
This will not work as is, because instead of using the entity class of Role, it is using the Role Facade. I have figured out a workaround for this, by setting an alias for the Entity with a slightly different name, such as RoleEntity so that
public function roles() {
return $this->hasMany('RoleEntity');
}
will work, however this doesn't seem like the most optimal solution.
My question is, is the practice ok? Or better yet, should this be happening at all? And if not, how do I fix it/where did I go wrong?
You have two classes with the same name in the same namespace. Use different namespaces so you can use the same class names.
I usually use \Models to locate my models classes.
At the top of each model file:
namespace Models;
In your controller or any part of your app:
\Models\Role::first();
Note that changing the namespace on your model will require you to add the namespaces of other classes i.e. Str, Eloquent, Url, Redirect, etc.
use Eloquent;
use URL;
In your model, you also have to pass the namespaces in the relationship functions, i.e.:
public function roles() {
return $this->hasMany('\Models\Role');
}
i think, In "CakePHP" one model is against each controller but i have multiple functions in single controller and each function represent different page and database table.
i.e
public function manage_categories(){}
public function manage_sub_categories(){}
above 2 functions are in Admin Controller but now the issue is how to create model against each function to represent database. each function has unique attributes in database.
One thing more either model name should be same to controller name "admin" or this name will be same as functions name. while in normal circumstances model name is same to controller name.
"Users" model name is used against "UsersController"
kindly guide me ti resolve above said issue. i tried enough to solve it bot couldn't.
Thanks in advance.
If you have two database tables it would be logical and best practice in terms of SoC to have two controllers instead of throwing a lot different things that don't belong into the same domain into a single controller.
Sometimes when you just want to use a part of data from an associated model you can access it through the associations:
$this->Model->SubModel->foo();
Also you say you have an admin controller which is a working but not very good approach. Instead CakePHP features prefix routing. So an action accessed like /admin/categories/some_action will route to the CategoriesController some_action() action.
"Users" model name is used against "UsersController"
Is wrong, by convention models should be named singular, not plural. Your UsersController won't find an Users model because it's looking for an User model.
And stay away from Model::query(), use the ORM instead as much as you can.
public function manage_categories(){}
public function manage_sub_categories(){}
Should become:
class CategoriesController extends AppController {
public function admin_index() { /*...*/ }
}
class SubCategoriesController extends AppController {
public function admin_index() { /*...*/ }
}
But assuming that sub-categories belong to a category which is the same table I don't see a need for a second model or second controller at all.
Can you help me on this one. I'm new in CodeIgniter and PhpStorm, I'm having a problem. The PhpStorm IDE is showing an error, even though the code works fine (the Persons(controller) class can't find the Person(model) class).
$data['persons']=$this->**person**->get_person(); = on this syntax from Persons class, there is a message "Field person not found in class Persons".
Can you enlighten me on how to resolve this, but actually the output is good and it retrieves the data without issue just a warning message in Persons class.
The person property ($this->property) is not explicitly declared as it is created and accessed via PHP's magic methods.
PhpStorm has no special support for CodeIgniter framework and cannot guess where $this->person is coming from and what type it is.
But you can help IDE -- just a small PHPDoc comment before the actual class -- using #property tag.
/**
* #property Person $person Optional description
*/
class Persons extends CI_Controller {
...and oh magic -- it works:
The answer from LazyOne did not work for me initially. After some testing I found out that my issue was upper/lower case related on how you declare the property in PHPDoc - hopefully the following observations can help someone else. This is what I have to declare my model class:
class Custom extends CI_Model {}
In my controller I load and use the model for example the following way:
$this->load->model('Custom')
$table = $this->Custom->get();
Now for phpStorm to pick up this class correctly I originally added a PHPDoc #property comment above a core class as described by others (either above the CI_Controller class or separate CI_phpStrom.php file) like this:
*
* #property Custom $custom
*
However, this didn't remove the issue, as the variable name becomes case sensitive in this case and I had to write:
*
* #property Custom $Custom
*
for my above controller code to pick up the class correctly. An alternative would be to use lowercase when calling functions (this works even if your model declaration used uppercase)
$this->load->model('custom')
$table = $this->custom->get();
The funny thing all this uppercase or lowercase didn't matter if I call my model class "Custom_model" - then it made no change if set the PHPDoc property variable to $Custom_model or $custom_model ...
Normally most people add the ‘_model’ suffix to the Model class names. I suggest that you rename your model with "Person_model" call your model "person_model" like this:
$this->load->model('person_model');
$this->person_model->get_person();
I think that you might find it an adequate solution!
I'm just studying CakePHP so sorry for any obvious mistakes.
I have created model class and changed default table name.
class Weathers extends AppModel {
public $tablePrefix = 'weather_';
public $useTable = 'forecasts';
function saveCountries($countries){
...
}
}
And my controller function
if (!$this->loadModel('Weather'))
exit;
$Weather = $this->Weather;
$Weather->saveCountries($countries);
I'm getting error on $Weather->saveCountries($countries);
Error: Table weathers for model Weather was not found in datasource
default.
Please help find out what I do wrong.
The Model class you defined is Weathers not Weather. So just change the class name Weather instead of Weathers and this is done.
Note the declaration of your Model class.
You've called it Weathers.
There is no problem with this. However, as you are trying to then load the model Weather (not the lack of plural in this case) CakePHP is constructing a model dynamically for you, instead of using your Weathers (plural) class.
The CakePHP standard is to use a singular name for models. I suggest that you rename your model class to Weather to avoid this issue. Once you make this change, the code that you have for loading the model will work as intended.