Many-To-Many relationship save fails - php

I have this Many-To-Many relation:
These are my Models:
Productvariant
class Productvariant extends DataMapper {
var $has_many = array('propertyvalue');
var $has_one = array('product');
}
Propertyvalue
class Propertyvalue extends DataMapper {
var $has_many = array('productvariant');
var $has_one = array('property');
}
Controller
$productvariant = new Productvariant(1);
$prodval = new Propertyvalue(1);
$productvariant->save($prodval);
Message
Unable to relate productvariant with propertyvalue.
Only thing I can find in the documentation is self Many-To-Many relationship and I seem to misread how they want you to use the models in that fashion.
Do I need to define a model for the extra table too?
==========================
UPDATE
I made an in-between Model for Many-To-Many relationship;
Model
class Productvariant_propertyvalues extends DataMapper {
var $table = '__productvariants_propertyvalues';
var $has_one = array('productvariant', 'propertyvalue');
}
Controller
$productvariant = new Productvariant(1);
$propval = new Propertyvalue(1);
$pv_vals = new Productvariant_propertyvalues();
$pv_vals->save(array($productvariant, $propval));
It works now, but shouldn't this be doable without the extra Model?

You either have a many-to-many between Productvariant and Propertyvalue, and then you define them as you did. Datamapper will automatically look for a junction table called "productvariants_propertyvalues", which contains the foreign keys to the two tables.
So your setup should work. They only issue that could pop up is that the CI plural() function that datamapper uses doesn't produce the correct table name, causing the not-found error to popup.
If you create an in-between model, you split the many-to-many into two one-to-many's. Not a problem, but whether or not you need it depends on your application design.
edit: I now see you have prefixed the table name with a double underscore. Datamapper will not generate that, so that is why the junction table can not be found. Either remove those, or switch to an advanced relationship definition in which you define the "join_table" manually.

Related

Eloquent (WITHOUT Laravel) get data from table with dynamic name

I'm sure this is a totally simple question but for the life of me I'm stuck here- we're using Eloquent outside of Laravel due to PHP restrictions. I have a support ticket tracking app that I'm trying to update.
The data structure of this app is such that each ticket is assigned a UUID on submission and a table with that UUID as its name is generated and all changes to the ticket are tracked as new entries in that table.
Following some tutorials on Eloquent I got our models and controllers set up and working but for each one I see that I'm defining the table name in the model itself. IE our ticket model is
namespace Models;
use \Illuminate\Database\Eloquent\Model;
class Ticket extends Model {
protected $table = 'tickets';
protected $fillable = [table columns here];
}
and anything called in the tickets controller correctly and successfully reads and writes data to our tickets table.
So... my question is: how would I go about reading/writing/creating/deleting those previously mentioned UUID tables?
I've tried the built in table selector (ie- DB::table(uuid here) and DB::setTable(uuid here) but to no avail. I get Fatal error: Call to undefined method Models\Database::setTable()
What I'm after is a model/controller that I can reuse for ANY dynamically-named table.
You could create a generic model and dynamically set the table name, like this:
namespace Models;
use \Illuminate\Database\Eloquent\Model;
class FormerUUIDTicket extends Model {
protected $table = 'some_table';
protected $fillable = [table columns here];
}
class SomeController
{
public function someAction()
{
$uuid = $_POST['uuid_field']; //some uuid, the table name
$model = new FormerUUIDTicket;
$model->setTable($uuid);
return $model->get(); //do anything using eloquent with proper table
}
}
Make sure that you always set the table name before use, or it will fail. Don't use static function either, for the same reason.

Laravel - Single Model for Multiple Tables

I want to use a single Model file for multiple tables.
Why???
The Table structure of all the tables is same
I have few columns to be stored as JSON Arrays and I would like to use Laravel's built in Json Serialization rather than manually serializing Arrays.
I have already read on laracast blog that it's not possible in Laravel but is there any other way to make it possible.
Thanks in advance!!!
You can just create a base model that has the logic that is common to all the models, and then create your individual models that inherit from the base model.
class Auto extends Model
{
protected $casts = [
'details' => 'json',
];
public function getWheelsAttribute()
{
return $this->details->wheels;
}
}
class Car extends Auto
{
// models your "cars" table
}
class Truck extends Auto
{
// models your "trucks" table
}
class Bus extends Auto
{
// models your "buses" table
}
Or, you could create a trait with the common functionality and use the trait in all your child models.
trait HasJsonDetails
{
protected $casts = [
'details' => 'json',
];
public function getWheelsAttribute()
{
return $this->details->wheels;
}
}
class Car extends Model
{
// models your "cars" table
use HasJsonDetails;
}
class Truck extends Model
{
// models your "trucks" table
use HasJsonDetails;
}
class Bus extends Model
{
// models your "buses" table
use HasJsonDetails;
}
Or, another option, if the table structure truly is and will always be the same, would be to combine all your tables into one table and use single table inheritance to have multiple models all use the same table.
With this method, you would add a type field to your table to tell you which class to use to model the individual row. It also requires some customization, but you can find an STI package to use, or follow this forum thread for more information:
https://laravel.io/forum/02-17-2014-eloquent-single-table-inheritance
This, of course, would still need to be combined with one of the methods mentioned above to share implementation logic across the multiple models.

Modeling an Object with one-to-many relationships (PHP)

I am trying to force myself to be consistent when modeling objects, but I'm just not sure what the best way is to create a class that has one-to-many relationships.
For example, lets say I have two tables in a database called Projects & Notes. A note can only belong to one project and a project can have many notes. Would the following be a good (best) way to model my project class? Or should the notes just be set to a separate variable in the controller and never be a property of project?
class Project extends BaseModel{
$id //string
$description //string
$notes //array of note objects
}
class Note extends BaseModel{
$id //string
$text//string
}
//In a Controller Class
$project = new Project();
$noteArray = new Note();
//Set the note property of project equal to an array of note objects
$project->setNotes($noteArray->findNotes($project->id));
I think there should be one more property in Note model that will reference to the Project model. Identificators of model MUST be an integer type
class Note extends BaseModel{
$id //string
$text//string
$project_id //int
}
So when you add a project, say it, with ID=5, You can add Notes with project_id = 5. And it will be one-to-many relatoionship.

laravel many to many relationship in this case

I have already checked this official example http://laravel.com/docs/eloquent#many-to-many-polymorphic-relations
but I still confused because I may have a different case.
I have a DetailsAttribute model which deals with details_attribute table.
I have a Action model witch deals with action table.
The relationship between them is many to many.
So I created a new table details_attribute_action with model DetailsAttributeAction
My DetailsAttribute model should have:
public function actions(){}
My Actions model should have:
public function detailsAttributes(){}
and my DetailsAttributeAction model should have functions but I don't know what they are.
My question is what is the code inside the previous functions please? and should really the DetailsAttributeAction have functions of not?
What you're looking for is a Many-to-Many relation, not one that is polymorphic.
http://laravel.com/docs/eloquent#many-to-many
Your code should look something like this:
class DetailsAttribute extends Eloquent {
// ...
public function actions()
{
// Replace action_id and details_attribute_id with the proper
// column names in the details_attribute_action table
return $this->belongsToMany('Action', 'details_attribute_action', 'details_attribute_id', 'action_id');
}
}
class Action extends Eloquent {
// ...
public function detailsAttributes()
{
return $this->belongsToMany('DetailsAttribute', 'details_attribute_action', 'action_id', 'details_attribute_id');
}
}
You won't have to worry about how to create the DetailsAttributeAction model in Laravel. It's simply a table to map the Many-to-Many relationships you've created.

CodeIgniter and DataMapper

I've read through a few different posts here and I can't figure out what I'm doing wrong.
My DB is setup like the following:
homes
- id
- address_id
- price
- etc...
address
- id
- home_id
- address1
- address2
- etc...
Then my models look like this, condensed.
home.php
<?php
class Home extends DataMapper {
public var $has_one = array('address');
}
address.php
<?php
class Address extends DataMapper {
public var $has_one = array('home');
}
Then my controller uses the following:
homes.php
class Homes extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->library('datamapper');
}
public function index() {
$homes = new Homes();
$homes->include_related('address');
$homes->get_iterated();
$this->output->enable_profiler(TRUE);
_p($homes); // Self made function that wraps a print_r() in two <pre> tags.
}
}
If I comment out these two lines I get the standard CI return array.
$homes->include_related('address');
$homes->get_iterated();
If I don't then I get a server error. This is my first time using DataMapper and I'm almost certain I'm doing everything wrong, but have no idea where to start.
UPDATE:
I figured out my issue. I had to change the DB table address to addresses and in my address.php model I had to specify var $table = 'addresses';
That fixed everything.
Yes you can specify the table name in your model. Also your example was wrong :
$homes = new Homes();
Should be
$homes = new Home();
I usually redefine the table name within my model to make sure everything is fine.
Your relations is wrong. I assume you are setting a One to One relation ship. The doc say :
http://datamapper.wanwizard.eu/pages/relationtypes.html
Because this is a One to One relationship, the relationship could have been stored in three ways:
As shown, on the workers table.
On the workplaces table, as worker_id
On a dedicated workers_workplaces join table, with the columns id, worker_id, and workplace_id
But here you have added *address_id* to home and *home_id* in address.
You have to choose between on. For example keep *home_id* in address and remove *address_id* in home.

Categories