Is there an easy way to manage many-to-many relationships in the new seeds feature of L4?
One way would be to make a seed for the pivot table, but I would be a lot of work.
Any thoughts on a good workflow for this sort of thing?
In the latest version of Laravel 4 you define the order that all the seeder scripts are run in the "run" method of the DatabaseSeeder class.
public function run()
{
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
$this->call('PrimaryTableOneSeeder');
$this->command->info('The first primary table has been seeded!');
$this->call('PrimaryTableTwoSeeder');
$this->command->info('The second primary table has been seeded!');
$this->call('PivotTableSeeder');
$this->command->info('The pivot table has been seeded!');
DB::statement('SET FOREIGN_KEY_CHECKS=1;');
}
You'll notice that I disable the foreign key constraints before and after running all my seeding. This may be bad practice but it's the only way I can use the truncate function to re-set the id count for each table. If you follow the guide on inserting related models this practice may be unnecessary.
class PrimaryTableOneSeeder extends Seeder {
public function run()
{
DB::table('primaryone')->truncate();
Primaryone::create(array(
'field' => 'value',
'created_at' => new DateTime,
'updated_at' => new DateTime
));
}
To use mass assignment as I'm doing in my example and as the latest version of the documentation does, you'll need to specify either some guarded or fillable columns for the model. To do this simply add property to your model like this:
class Primaryone extends Eloquent {
protected $guarded = array('id');
Laravel seed files are regular PHP scripts (except they need to return an array). You can query the database in seed files (using Eloquent, Fluent builder or even PDO).
One way to tackle the many-to-many problem is to deliberately name your seed files so that the pivot table is populated last... For example, you could prepend a numeric value to the file name (i.e. 1_authors.php, 2_books.php, 3_authors_books.php etc.). Artisan sorts the filenames alphabetically before executing them.
I have posted a small tutorial on Laravel 4 database seeding - this should get you going. Additionally, you may consult the official doc on seeding.
Seeding is for simple information, test data and static information. I wouldn't recommend using it to handle relationships. Personally, I only use it for 2 or 3 record per table, to help test my application.
When developing your application, think about working on the data entry (admin) area first then the front end. That way you can easily add test data.
Related
I'm really new to cakephp (3). I have a general question about baking models, views and controllers.
Do I have to completely plan and create the database scheme before baking any m., v. or c?
I'm afraid of overwriting my codes, when I extend my database-scheme. I'm thinking of a situation like this:
I have two tables "Articles" and "Users". I baked mvc-s, having a small but complete website. I tweaked the Users-Model/Entity for some validator-reasons (e.g.).
Now, two weeks later, I want to add a "Group" table, where one user can belong to many groups.
Normally, I could rebake the Users-mvc-files. But that would overwrite my whole website.
Do I make a mistake? Do I have to manually modify the mvc-files when extending tables?
What is the best practice for extending a cakephp-website?
Many thanks in advance.
You could just bake the MVC for the new table, Groups (should be plural), and then update the associations, if any, in other tables. For example, if Users belongs to Groups, after baking the Groups table, you could add:
// in /src/Model/Table/UsersTable.php
$this->belongsTo('Groups', [
'foreignKey' => 'group_id'
]);
Of course, this assumes you've added the 'group_id' field to the Users table in your database.
This is a fine solution if your table is small and your data model remains fairly static. But if you are working with many tables and you are still regularly making changes to the model, I would suggest doing what I did after blowing away all my controller changes a couple of times.
CakePHP 3 makes very cool use of Elements in it's Controller templates. You can copy the cakephp vendor templates into your src directory, and then provide your additional controller methods (like login()/logout() in UsersController) as elements. Then test for the model and include the appropriate elements for that model.
This way you can bake away and not worry about losing all your changes.
Yes, generally you have to plan for database scheme before baking your MVC.
You should manually do the changes if any alter/changes become in the table otherwise the bake will override all the codes you did.
All the very best
I use the Zend 2 Framework to build my web application. I implemented my database table models by this tutorial: http://framework.zend.com/manual/2.1/en/user-guide/database-and-models.html
I have a many-to-many relationship between two models in my database. To get data from them I googled and found this link: http://mattmccormick.ca/2010/04/24/how-to-easily-create-models-and-table-relationships-in-zend-framework/
The problem is that all the table models extends from Zend_Db_Table_Abstract in the example. I don't know how to get data from the models.
I have a table containing votings, every voting has a unique hash id. Every voting also has tags. Therefore I defined a table tags with all the tags available and a voting_tag_map where all many-to-many relationships are mapped.
What I have tried so far is the following, that's code from my VotingTable class:
public function getTagsByVoting($votingHash){
$select = $this->tableGateway->getSql()->select();
$select->from(array('v' => 'voting'))
->join('voting_tag_map', 'v.voting_id=voting_tag_map.voting_id')
->join('tags', 'voting_tag_map.tag_id=tags.tag_id');
$resultSet = $this->tableGateway->selectWith($select);
return $resultSet;
}
It says then:
Since this object was created with a table and/or schema in the constructor, it is read only.
Thats because of the from() method. If I delete the from() method, it says:
Statement could not be executed
Can anyone help me please?
Since this object was created with a table and/or schema in the constructor, it is read only.
This error is because you are trying to set the table name in the from clause, but it's already been set in the contructor of the TableGateway, and you can't change it once set.
If you really need to do this then you can extens AbstractTableGateway yourself then you won't have to add a string tablename to the contructor, but you don't really need to use an alias on your main table...
The SQL error you get when you comment out the from() method will be due to your referencing the votes table as it's alias 'v' in your join, when you are not using the alias v, try changing it to 'voting.XXX' from 'v.XXX'
I've got three tables (there's actually several more, but I only need the three for this problem). Applications, Appattrs and Appcats. In CakePHP parlance (as best as I can since I'm still learning the framenwork) Applications hasMany Appattrs and Appattrs belongsTo Applications. Easy.
The problem comes when I want to associate Appattrs and Appcat - the association is predicated on a field value and a corresponding foreign key in Appattrs. For instance:
If appattrs.type = 'appcatid' then appattrs.value would point to a record in the Appcat table.
The appattrs table holds static data appattrs.type='dateadded' and value='201201011300' as well as foreign key references. I'd rather not get into a discussion as to why data is stored this way, I just want to figure out how to create associations that will let me pull an application record, the associated attr records and then an attr record with its associated row from the appropriate table. Dynamically.
It seems to me that I should be able to create a model based on a query and then associate that model - I just can't seem to figure out how to do that.
--
If I need to post schema for the three tables, I can. I can also post my current model code, but honestly, right now it's just association variables so I don't think it'll get anyone anywhere.
Thow I do not understand the logic behind this design, I thing what you are looking for
is Creating and Destroying associations on the fly.
On this section of CakePHP Docs, it describes how you can associate models from within the corresponding controller.
So, for example, when you want to save specific data to Appattr model you can do some data checking and create your association using bind() method.
A very abstract approach to the above would be something like this
public function yourmethod() {
...
if ($this->request->data['Appattr']['type'] == 'sometype') {
$this->Appattr->bindModel(
array(/*Your association*/ => array(/* Your attributes...*/)
);
/* Rest of the logic follows */
}
}
This way you get your job done, but it's very possible to end up having very complicated
data in your database and thus having very complicated code.
I hope this helps
I know you can define table relationships fairly easy with $this->belongs_to(), $this->has_many() etc, but what i don't understand is how the relationship table is created; the table that binds the two tables together (i forgot what the term is called).
Let's say i'm creating a users table. I want that user to belong to a certain "Role". There are multiple roles, and every role can have multiple users. I will need to also create a roles table for that. So far, so good.
But after reading the documentation, it says i should add the $this->belongs_to() in the model, not the migration itself. When, and how is the relationship table created? If i create the roles and users tables, and add $this->belongs_to('roles') to the users model, and $this->has_many('users') to the roles model, will the middle table be created automatically?
When creating a migration you can specify foreign keys on your tables,
i.e.
public function up()
{
Schema::table('roles', function(Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
//rest of fields then...
$table->foreign('user_id')->references('id')->on('users');
});
}
This will create a foreign key on the user_id column on the roles table.
The benefits of foreign keys is that when an update or delete is made the foreign key table will be automatically updated or "cascaded" great description found here
As described on the Laravel documentation you could also specify your cascading on update using the following syntax
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
I would do a bad job of trying to explain it better than the documentation does so please have a read through the "Relationships" section of the Eloquent ORM documentation to see how its done.
It looks like a few of the initial questions were never answered, i.e. "When, and how is the relationship table created" & "will the middle table be created automatically":
As far as I am aware, these tables need to be created manually. So create the migration file like so:
Laravel 5
php artisan make:migration create_role_user_table
Laravel 4
php artisan migrate:make create_role_user_table
Note that the names are singular, and are presented in alphabetical order.
Then in the migration something like:
public function up()
{
Schema::create('role_user', function($table) {
$table->increments('id');
$table->integer('role_id');
$table->integer('user_id');
$table->timestamps();
});
}
Hope that helps. I'm not sure if the timestamps are needed in Pivot Tables or not, so please experiment.
Though its an old Post, I though I can contribute something updated. For Laravel5, Jeffrey Way has developed a package Laravel5 Generators-extended which enhance the generator capability of php artisan for
make:migration:schema
make:migration:pivot
make:seed
For many-to-many relation between users and role, you can just use
php artisan make:migration:pivot users role
and it will generate the required migration class. You don't need to code manually for this.
As far as I know, no relationship table will be created. What you will need to do is have a role_id on your users table, so that when you create a user, the ID of the role will be stored there. This will enable you do select all users where role_id == '1' or whatever it may be.
For example:
$admins = User::where('role_id', '=', 1);
Where on the ROLES table the record with ID='1' is admin.
So again to answer your question, no relationship table is created, instead the relationship exists within your two tables in the form of a role_id column for each user. Out of interest, are you using foreign keys?
If you want to have a relationships table you could create one called user_roles or something and store the role_id and user_id in there, however I think its easier to use the above method as then you can use all the Laravel/Eloquent goodness.
Hope this helps :)
This video helped me.
https://laracasts.com/series/laravel-5-fundamentals/episodes/14
What was surprising for me was that only one side of the relationship needs pointer_id in migration table, not both. For example, if we have Author with many Articles, we only add
$table->integer('author_id')
to article migration and thats it.
I know this is an old post but as I had the same question in mind. I've found the solution in the Laravel manual (5.0) where it is described that for this particular many-to-many relationship you can create the table manually and then declare the type of relationship into Model in this way:
return $this -> belongsToMany('App\<Model>', '<table_created_manually>');
or if you want to use specific associated keys:
return $this -> belongsToMany('App\<Model>', '<rel_table1_table2>' '<table1>_id', '<table2>_id');
Hope this can help.
I tried querying the Db with this bit of code:
Makesite.objects.values_list('ref_id', flat =True)
and it returned [1,2,None]. Which I found to be moderately confusing. I assumed that python saved the instances by their own names and not numbers that it just assigns to them. Any help with the code or an explanation to why python saves them as numbers and not their names would be awesome thanks.
In models.py
class Makesite(models.Model):
sitename = models.CharField(max_length=100, unique = True)
siteinfo = models.ManyToManyField(Siteinfo)
ref_id = models.ManyToManyField(RefID)
report = models.ManyToManyField(Report)
Django doesn't save m2m by their "names". It uses their primary keys (in your case - integers). You can check it, by viewing your DB tables.
When you just use something like makesite.sitename Django makes anither query to fetch sitename instance.
But when you use values_list you don't want extra queries or joins, that's why Django returns data from a single table. And all that it can get form there is a primary key.
If you want to optimize your related queries take a look at select_related / prefetch_related methods or use caching.