I want to get some details about recommended work process for Yii. Imagine you already have some database and some model for it. And in one day you need to add a new field to the model. In Django, you can just modify models.py file and then run manage.py makemigrations && manage.py migrate - it will analyze changes, create migration file and apply the changes to the database. But what I should do in Yii?
I see only following way from the docs and manuals:
Create empty migration
Try to write necessary changes in Yii-migration syntax (it may be not so obvious for altering column and adding foreign keys, more difficult than just writing SQL queries).
Run yiic migrate
Generate Model code using Gii for new database structure and copy-paste new fields to your existing Model file.
From my point of view, it leads to lot of useless work by creating migration in addition to modifying Model. So, instead of just modifying model like in Django, I have to use strange migration syntax in Yii and then modify model manually. It it really the way it supposed to work? Isn't it possible to simplify it somehow?
I'm using below approach for like 5-6 month and its work perfect:
create new folder inside models folder name it entities.
generate all models you need using gii and
generate all models you need using gii
a) in model path field use new folder, "entities" instead of models folder
b) in model class field, add "Entity" as model name postfix
now in models folder, make new PHP class and named it for example "Gift" and extends it from "GiftEntity"
add new folder, "entities" in preload imported classes.
now, when you make new migration and change your models in db, use gii to regenerate your entity models "GiftEntity", and all your codes in extended model "Gift" are untouched.
Related
Coming from a long Symfony-Doctrine background, I have started learning Laravel 8.
One of my first discovery was that migration needed to be manually created after using make:migration (from what I understood thus far) in both Models and Migration.
Symfony, with Doctrine, allowed a bunch of automatisation, and I only needed to create the field or relation from the Model (php annotation or yaml) - before launching doctrine:schema:validate and make:migration
https://symfony.com/doc/current/doctrine.html#migrations-adding-more-fields.
Let 'say I create a Post and Comment entity, with a One-To-Many relationship.
If I define the relation in the php classes
class Comment extends Model
{
/**
* Get the Post owning this comment
*/
public function post()
{
return $this->belongsTo(Post::class);
}
}
Post class
class Post extends Model
{
/**
* Get the comments for the blog post.
*/
public function comments()
{
return $this->hasMany(Comment::class);
}
}
Is possible to generate the migration scripts that would update the database and create these relation ship ? Or will I have to rewrite it twice (once in the PHP class with hasMany/BelongsTo then again in the Migtration file ?
Not having a central file to map/read a model (which linkied php and database) seems weird to me now.
I've only started but the documentation does not seems to mention anything equivalent
Edit : for more clarity : I'm asking if there are equivalent of Generating migration code/script from models (or a central mapping file : yaml or annotation ) without having to write fields to both migration and models ( in $fillable or other fields...)
Edit 2 Closest thing I could find is this
https://github.com/laracasts/Laravel-5-Generators-Extended
Another use case where this is cumbersome : many-to-many migrations
Having to manually write that third middle table from scratch is really something I wish was made automatically.
In laravel framework despite other famous fameworks like symfony or python django, you're responsible for making database migration files. By this way, you are free to customize your database schema and add any database constrains like (unique constrain, relation constrains and etc.). Also you can add any raw sql using \DB::unprepared(); in your migration files.
I can tell you that it is normal to be a little confuse about this flow, because you've used to this kind of automation in other frameworks like I did, but beilieve me, you get to used to this flow.
By the way, there are some packages out there that do this automation (create migration files according to model) for you.
For creating a migration you need to run command
php artisan make:migration migration_name
And for creating a model you need to run command
php artisan make:model table_name
Refer to this link
https://laravel.com/docs/8.x/eloquent#generating-model-classes
By creating a model you create a table, where you can define the columns types and different properties and define the relationship with other tables.
By creating a migration file you can define the table columns and the constraints.
Actually, i'm a laravel developer, recently moved to yii and i found gii was there. I can create models, controllers and CRUD facilities with gii... and that's great!
But if I a add more fields in a table or simple delete a field in a table I have to recreate model and controller with gii, otherwise it gives error. It's really taking my time. Is there any other way to do it, because I searched it and found nothing so far about it. People are suggesting command line, but using gii, is it possible?
Why don't you just create a gii model again, once a new field is added.By the looks of it if you do not want to write code again then gii will give an option to modify the existing files and add the fields on its own.Simple as that.
But there is an disadvantage to this,if you have made some modifications as in for logic then that will get overridden once you modify the files using gii.But I suggested this because this fits in your business logic or as far as I can grasp it :p
My question is if it is possible to add all the fields directly to a new model via Eloquent.
I guess it would be something like
php artisan make:model MyModel --fields=?
However, I can't find anything related with that. Anyway, I have to generate a lot of model and any trick would be really appreciated.
Thanks in advance
If you mean table's column by fields then:
Firstly you don't need to define fields in modal. I mean in Laravel no need to define fields while creating model. Besides, model automatically work with your database table's columns as its property.
So, now you may want to define columns while creating migration, not while creating model. There is library to serve this demand named as Generator(https://github.com/laracasts/Laravel-5-Generators-Extended) maintained by Laracasts.
Using this generator you can generate migration file to create table in DB specifying their column names and their type also. Here is a example from their Github repo, how you can do this:
php artisan make:migration:schema create_users_table --schema="username:string, email:string:unique"
You can checkout their documentation for more information. Best of luck.
It's not possible with make:model or make:migrations commands, but you can create your own console command and add this feature by yourself.
Also, take a look at source code of make:model and make:migration commands to get some ideas on how to do that.
it looks like only built in options are --migration and -m to include a migration with the model generation. L5.3 Docs
There does look like there is a package for L5.0, which looks like it would work in 5.*+. It is put out by Laracasts:
https://github.com/laracasts/Laravel-5-Generators-Extended
It also looks like you can make a custom solution as well:
https://laracasts.com/discuss/channels/tips/l5-artisan-command-makemodel
Hope that helps!
No options while creating a model,
This is my terminal output (laravel 5.3) while i check,
You don't need to mention fields while creating model.
Ex:- based on the rules you should keep the names as like below,
model name as User
table name as users
then the model automatically handle everything, you don't need to mention the table/fields name.
I was looking for the same thing myself, as I used to work like that in previous frameworks, but could not find it, or at least not as I wanted it, so I did my thing. You can check it out if you like:
https://github.com/Triun/laravel-model-base
It will read your database, and create the laravel eloquent models for you.
It is meant to be very flexible, so the configuration may be a little complex, and I guess that I didnt' catch up with the documentation, but you can ask me if you don't know how to make it do what you want.
Basically it has 4 customization levels:
By out of the box modificators, configurable by the config files.
Including interfaces and traits to your auto-generated models.
Create your own modificators. Classes where you receive the model skeleton before it is saved, so you can add or remove properties, methods, etc.
Generate the model base, but edit yourself the final model.
And, of course, suggestions and contributions are more than welcome.
I just migrate to yii and i created a model which it created an CActiveRecord with gii and after that i make some changes in database then it make me confused, now my question is :
1 - Should i recreate Model with gii after any change to database ? Why Active record in yii is much complicated than other frameworks like zend or codigniter !?
Edit :
If we should not change Model Class, where should we put our database functions !!? aren't Model is there for doing so?
If I generate model with gii its only one-time job. To start quickly using this model. After that if you alter your database structure( btw you didn't tell what kind of changes you made) you can change model manually.
If you generated model via gii and didn't change model you can regenerate it again (because no manual changes made).
If you already changed it there is no hard work to change it (and take journey of learning about ActiveRecord).
Just for learning create model from scratch (without gii).
You can always use Gii to preview the changes that it wants to apply to the existing model (using the diff link). Then you can apply them, but in case you have inserted custom rules inside the model (rules() method), they will be overwritten. And yes, if you do any changes to your database tables, you will have to update your CActiveRecord subclasses (your models), otherwise Yii will not be able to see your new fields or fail if it tries to access fields that it thinks it has but were deleted from the database.
Nothing stops you from writing your custom methods inside the model. But what exactly do you mean by "put our database functions"?
EASY
1) Into your aplicacion index.php create global variable
<?php
$GLOBALS['database'] = "mydbname"; //database name
// change the following paths if necessary
$yii=dirname(__FILE__).'/../yii/framework/yii.php';
$config=dirname(__FILE__).'/protected/config/main.php';
// remove the following lines when in production mode
defined('YII_DEBUG') or define('YII_DEBUG',true);
// specify how many levels of call stack should be shown in each log message
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
require_once($yii);
Yii::createWebApplication($config)->run();
2) Into my model create a construct method
class Employees extends CActiveRecord
{
function __construct()
{
$dbname = $GLOBALS['database'];
Yii::app()->db->setActive(false);
Yii::app()->db->connectionString = 'mysql:host=localhost;dbname='.trim($dbname);
Yii::app()->db->setActive(true);
}
3) How to use into my controller
public function actionVer3()
{
$GLOBALS['database']="classicmodels"; //dbname
$employee = Employees::model()->findByAttributes(array("employeeNumber"=>"1002"));
print_r($employee);
echo "<br><hr>";
//$this->render("index");
}
Easy way tnx.
I think, You should ideally recreate the model after DB structural changes.
In our project, We are following the rule,
Do not make any changes in the models generated by gii. So that if
there are DB changes in future, we could directly regenerate the
models and will have no merging efforts.
This is also inline with philosophy of design,
**Objects** hide their data behind abstractions and expose functions that operate on that data.
**Data structures**
expose their data and have no meaningful functions. It only has methods to operate on data.
ActiveRecords(models in yii) are nothing but data structures.By adding business rules in ActiveRecords, you are mixing your data structures and objects.
Hey.
I'm having a hard time migrating changes I've done i my config/doctrine/schema.yml file.
I added the column age to the user table. Then I did a php symfony doctrine:generate-migrations-diff followed by php symfony doctrine:migrate .
Looking in my database, the column age is now added, without deleting any data.
But, my /lib/model/doctrine/base/BaseUser.class.php is not changed, there is no age field or functions for age . So I also did the command php symfony doctrine:build-model . Finally the model is updated/migrated too.
So I wonder, is this the only way? Seems like a lot of work, and I'm afraid to miss something each time doing it.
Could I go right into phpmyadmin, add changes in the database there and just do a php symfony doctrine:build-schema , and like that skip the migration part (two commands).
Also when the comes to use of models, am I right that /lib/model/doctrine/User.class.php is where I can make functions and such for my User "data class"? Like, making a function isFemale . If not, where would that kind of function be?
This might be a bad question, but why is the model layer inside the /lib/doctrine path? As far as I have learned, you keep modules inside apps, where you create your view and controller. Why should the model be outside. Like this I can make models without attached controller and view?
Thanks.
Why should the model be outside
Because models can be used everywhere in your project, in example, in different applications and modules.
Could I go right into phpmyadmin, add changes in the database there and just do a php symfony doctrine:build-schema , and like that skip the migration part (two commands).
Of course you can, but migrations are a good approach to track your schema when deploying to production or working in team.
Here how I use doctrine migrations (simple use-case):
Add a column age to my User model in schema.yml
./symfony doctrine:generate-migrations-diff. Migration class(-es) have been generated.
./symfony doctrine:migrate. Column age successfully added to table.
./symfony doctrine:build --all-classes. Build forms/filters/models
That's it. The main idea is that doctrine:generate-migrations-diff class:
Gathers information about all your models' structure (php-representation of schema.yml)
Compares your schema.yml and info from (1)
Generates migration classes based on difference
Also when the comes to use of models, am I right that /lib/model/doctrine/User.class.php is where I can make functions and such for my User "data class"? Like, making a function isFemale . If not, where would that kind of function be?
Yes, you can add such method to User model because it's about users.