Codeigniter MY_Model composite primary key - codeigniter

I'm working with a base class MY_Model for accessing the database, which contains all the CRUD methods. The model which I'm using is Jens Segers' MY_Model:
https://github.com/jenssegers/CodeIgniter-My-Model
Now, I have a table in my database which contains a composite primary key (article_id and tag_id). Normally, when the primary key contains only an ID for instance, I could just use:
protected $primary_key = "id";
Is there a possibility for a composite primary key, or should I add a column ID to be the only primary key?
Thanks in advance.

Don't sacrifice your database structure because the custom library you are using doesn't support exactly what you need.
There's a work around however:
That library uses CI's database library and uses the $primary_key in the db->where() function.
That function accepts the following argument formats:
$this->db->where('name', $name);
$this->db->where($array);
$this->db->where($where);//$where is a custom MySQL query string
Therefore, you CANNOT set a composite primary key by setting:
$primary_key = array("article_id", "tag_id");
as the library constantly uses the first method of the where() method above.
Instead, just supply methods like get() or insert() (or other) each time with array("article_id" => $article_id, "tag_id => tag_id).
The database will throw an error if you try and insert anything matching your primary key, so you can deal with that then.

Related

Implementing Composite Keys in CodeIgniter Models

Is there any way you could implement composite primary keys using Models in CodeIgniter 4?
Like this?
class SomeModel extends Model{
protected $table = 'table';
protected $primaryKey1 = 'primary_composite_id1';
protected $primaryKey2 = 'primary_composite_id2';
protected $primaryKey3 = 'primary_composite_id3';
// numbers in the identifiers were only added for clarity
...
}
I think you can define the table structure using the Forge class. Here is a snippet of how I defined the table in Migrations.
in SomeMigration.php
class SomeClass extends Migration{
/* added fields here */
...
// Set them as foreign keys
$this->$forge->addForeignKey('item_id', 'item', 'item_id', 'CASCADE', 'CASCADE');
$this->$forge->addForeignKey('poster_uid', 'user', 'user_id', 'CASCADE', 'CASCADE');
$this->$forge->addForeignKey('customer_uid', 'user', 'user_id', 'CASCADE', 'CASCADE');
// Set them as primary keys
$this->$forge->addPrimaryKey('item_id');
$this->$forge->addPrimaryKey('poster_uid');
$this->$forge->addPrimaryKey('customer_uid');
...
}
Also, if setting composite primary keys in Models are not possible, should I
Create a new primary key column for that table instead?
Leave out the $primarykey value as empty and use just use queries (e.g. using WHERE)?
Use any one of the columns(set as PK) in the table as the value for $primarykey?
questions were created based on this post Codeigniter MY_Model composite primary key, since the answer did not directly answer the question
I am currently using the framework for our school project. There was none mentioned in the documentation, so I got stuck. Any kind of alternative solution is very much appreciated. Thanks! Cheers!
I have run into the same problem these days.
It seems that Codeigniter doesn't support this functionality for the model's primary key.
I searched in documentation and in Model's source code and I saw that it handles the primary key like one value.
e.g. at models find method I can see this code:
$row = $builder->whereIn($this->table . '.' . $this->primaryKey, $id)
In my case I will add an extra ID column and use this as a primary key. If I find a better alternative in the future I will update here.
Best Regards

Laravel Auditing - How To Get Specific Column Using Eloquent Model Method

I'm using Laravel Auditing Package to trace changes on my models.
I want to get a specific column of the foreign key in it's primary table before recording the events (create, update, delete) in the audit table.
There is a way the package helps get all the attribute of the foreign key, it's called Audit Transformation but it generates an error for me when displaying the details in the table i want to know if there's any eloquent model method to get the specific column info i need instead of using getattribute() method which gets the entire row of the item_id.
Audit Transformation Method
public function transformAudit(array $data): array
{
if (Arr::has($data, 'new_values.item_id')) {
$data['old_values']['item_name'] = Item::find($this->getOriginal('item_id'));
$data['new_values']['item_name'] = Item::find($this->getAttribute('item_id'));
}
return $data;
}
This is how it's stores in the database ephasis on the item_name.
{"item_id":"1","qty_received":"2","delivered_by":"John",
"received_by":"Abi","supplier":"Stores","date":"2019-11-26","item_name":{"item_id":1,"item_name":"Toner","colour":"Black","status":"Active",
"created_at":"2018-10-25 17:55:26","updated_at":"2018-10-25 17:55:26"}}
And this is the Item table schema
So in my scenario i'd want to store the item_name as Toner not the entire row of the item_id
Any suggestion will be welcomed, thanks in advance.
Add ->item_name->item_name after the function of Find.
if (Arr::has($data, 'new_values.item_id')) {
$data['old_values']['item_name'] = Item::find($this->getOriginal('item_id'))->item_name->item_name;
$data['new_values']['item_name'] = Item::find($this->getAttribute('item_id'))->item_name->item_name;
}

Laravel - Using different field names in the database (userid in a table and created_by in other)

I am trying to use a table for my Users and separate table for users' Projects in my database. However I want the names of the fields to be different for user id. What I want to take the id from the 'Users' table; and while saving the created project to the database, use that (user) id as created_by_id in Projects table.
public function store(CreateProjectRequest $request)
{
$project = new Project($request->all());
Auth::user()->projects()->save($project);
// Project::create($request->all());
return redirect('pages/home');
}
Also in Users.php, I added:
public function projects()
{
return $this->hasMany('App\Project');
}
The commented field is working on its own. However, I guess my problem arises because when I comment that line again, and add the other two lines ($project... and Auth::user... bits), I guess it is assuming I have a field in the Projects table named id.
I thought I would work around this problem with changing the primary key but I couldn't find how to take the Auth::user()->id; and make it write that value in created_by_id in a secure way. This is what I found though:
class Project extends Eloquent {
protected $primaryKey = 'created_by_id';
}
Edit: I don't think changing the primary key is my solution.
You can pass a second and third parameter to hasMany() method to specify the keys to use. Documentation
public function projects()
{
return $this->hasMany('App\Article','userid','created_by');
}

Use a different column on a many-to-many relationship in Laravel 4

I've got a situation in a project where I need to form a relationship between a primary key on one table and an indexed column (not the primary key) on another. Here's a sample of the database layout:
courses table
id
level
resources table
id
courses_resources table
course_level
resource_id
In my CourseResource model I have the following:
public function courses(){
return $this->belongsToMany('Course', 'courses_resources', 'resource_id', 'course_level');
}
Which works fine.
Then in my Course model I have:
public function resources(){
return $this->belongsToMany('CourseResource', 'course_resources', 'course_level', 'resource_id');
}
Which doesn't work. When I look at the last query performed on the database, it appears Laravel is searching the course_level column using the course's ID. That makes sense, but is there any way to use the level column for this relationship?
Eloquent BelongsToMany depends on PKs, so there is no way to do that with its methods.
You need custom relation object for this, that will check for given field, instead of primary key.
A quick and hacky solution would be this:
// Course model
public function getKey()
{
$relation = array_get(debug_backtrace(1, 2), '1.object', null);
if (method_exists($relation, 'getForeignKey')
&& $relation->getForeignKey() == 'courses_resources.course_level')
{
return $this->getAttribute('level');
}
return parent::getKey();
}
However if you would like to use it in production, do some extensive testing first.

Getting variable passed in URL with Laravel 4

I want to get the ID which was passed in the URL but it seems something goes wrong!
This is my routes.php
Route::get('/poste/{idp}',array('before' => 'members_auth',function($id){
//dd($id);
$post =Posts::where('idp','=',$id) -> get();
$titre=$post->titre;
$desc=$post->description;
return View::make('showPost',array('title'=>$titre,'description'=>$desc));
}));
And this is my View
<a href="/poste/{{$userpost->idp}}">
The error was Undefined property: Illuminate\Database\Eloquent\Collection::$titre
It is quite common issue when you start with Eloquent ORM. Basically get() method always returns Collection of objects, even if there is only one found. Sure enough Collection object has no titre property. If idp is primary key for your Post model, you should use find() or findOrFail() method instead.
$post = Posts::find($id);
As Laravel documentation states:
Note: Eloquent will also assume that each table has a primary key
column named id. You may define a primaryKey property to override this
convention. Likewise, you may define a connection property to override
the name of the database connection that should be used when utilizing
the model.
You are free to override your primary key.
class Posts extends Eloquent
{
protected $primaryKey = 'idp';
}

Resources