Cakephp and database with uncomon structure - php

how can I access any table from database in my model?
For example, I have Indexcontroller and code inside it:
$results = $this->Index->query("SELECT COUNT(*) FROM my_own_table");
Error: Database table indices for model Index was not found.
So, as I understand, I can access only table with naming related to model/controller name. But what to do if I can't modify the table naming and I want to access it's data?

You're not limited to using a model that's directly associated with your controller (this is just default behaviour); you can use any model.
To achieve what you want, create a new model for this table, eg. MyOwnTable, and in your controller, you can add this property to the class:
public $uses = array('Index', 'MyOwnTable');
Now you can access MyOwnTable using CakePHP's built in ActiveRecord functionality:
$results = $this->MyOwnTable->find('count');
If you have other tables you want to access, simply create models for those and add them to the $uses property. (You can also use $this->loadModel('Model') inside the action if you prefer).
If you have a table name that isn't very readable (eg. my_tb_own_1_x or some such), you can call the model class something human readable (eg. MyTable), and add the $useTable property to the model:
public $useTable = 'my_tb_own_1_x';
/* and change the default primary key if you have an unusual one */
public $primaryKey = 'my_tb_own_1_x_idx_pk';
See the CakePHP manual for more info on how to change default model and controller behaviour:
1.3 - Model Attributes
2.0 - Model Attributes
1.3 - Controller Attributes
2.0 - Controller Attributes

Nope. You can access different tables. However, CakePHP stumbles over the fact that the table that is associated by default to the Index model doesn't exist.
In other words, the model Index expects a table 'indices' to exist (and an error is thrown when it doesn't). You can do one of two things:
Create a table indices
Add the following to your Index model: var $useTable = false;
If you have any use for an indices table I'd go with option 1. If you're not going to use the indices table, go with option 2.
If you go with either step 1 or 2, your example should start working.

Related

Does a one-to-one relationship in Laravel always need first()?

I have a one-to-one relationship between User and UserSettings models,
But (after $user = auth()->user()) when I try $user->settings()->something it throws an Undefined property error.
It's gone when I use $user->settings()->first()->something...
My question is, is this how it's supposed to work? or am I doing something wrong?
You cannot directly run $user->settings()->something.
Because when you call $user->settings(), it just return Illuminate\Database\Eloquent\Relations\HasOne object.
So it is not the model's object, you need to take the model's object and call its attribute like this.
$user->settings()->first()->something;
Dynamic Properties
Since you have one-to-one relationship between User and UserSettings.
If you have a one-to-one relationship in your User model:
public function settings()
{
return $this->hasOne('App\Models\UserSettings', 'user_id', 'id');
}
According to Laravel doc
Once the relationship is defined, we may retrieve the related record using Eloquent's dynamic properties. Dynamic properties allow you to access relationship methods as if they were properties defined on the model:
Eloquent will automatically load the relationship for you, and is even smart enough to know whether to call the get (for one-to-many relationships) or first (for one-to-one relationships) method. It will then be accessible via a dynamic property by the same name as the relation.
So you can use eloquent's dynamic properties like this:
$user->settings->something; // settings is the dynamic property of $user.
This code will give you a result of collection.
$user->settings;
So calling 'something' is not available or it will return you of null, unless you get the specific index of it.
$user->settings()->something
while this one works because you used first() to get the first data of collection and accessed the properties of it .
$user->settings()->first()->something
The first method returns the first element in the collection that passes a given truth test
see docs here laravel docs
If you want to get the user settings itself simply do this:
$user->settings
Then you can get the fields of the settings doing this:
$user->settings->something
When you do this $user->settings() you can chain query after that. E.g.
$user->settings()->where('something', 'hello')->first()
That's why the output of $user->settings and $user->settings()->first() are the same.
Auth only gives you user info;
Try the following code:
$user = User::find(auth()->user()->id);//and then
$user->settings->something;

SQLSTATE[42S02]: Base table or view not found laravel

So, going into the problem straight away. someone told me that we dont need to make a pivot table if we only want to have ids of the table. laravel can itself handle this situation. I dont know how this works. I have a table community and another table idea. relation is like this;
One community can contain many ideas and an idea can be found in many
communities.
Relation in idea Model:
public function community() {
return $this->belongsToMany('App\Community')->withTimestamps();
}
Relation in community Model:
public function idea() {
return $this->belongsToMany('App\idea');
}
Now i want to fetch all the records related to a single community to show on its page Let's say the community is Arts.
Here is Controller function:
public function showCommunities($id) {
$community = Community::findOrFail($id)->community()->get();
return view('publicPages.ideas_in_community', compact('community'));
}
When i attach ->community()->get() to the Community::findOrFail($id) Then it throws the error
SQLSTATE[42S02]: Base table or view not found laravel
Any help would be appreciated.
Edit:
Logically, this piece of code Community::findOrFail($id)->community()->get() should be like this Community::findOrFail($id)->idea()->get(). Now it is true but it has little issue. it throws an error
Fatal error: Class 'App\idea' not found
The way you define the many-to-many relation looks ok - I'd just call them communities() and ideas(), as they'll return a collection of objects, not a single object.
Make sure you use correct class names - I can see you refering to your model classes using different case - see App\Community and App\idea.
In order to find related models, Eloquent will look for matching rows in the pivot table - in your case it should be named community_idea and have 3 fields: community_id, idea_id and autoincrement primary key id.
With that in place, you should be able to get all ideas linked to given community with:
$ideas = Community::findOrFail($communityId)->ideas;
If you need communities linked to given idea, just do:
$communities = Idea::findOrFail($ideaId)->communities;
You can read more about how to use many-to-many relationships here: https://laravel.com/docs/5.1/eloquent-relationships#many-to-many
someone told me that we dont need to make a pivot table if we only want to have ids of the table
The above is not true (unless I've just misunderstood).
For a many-to-many (belongsToMany) their must be the two related table and then an intermediate (pivot) table. The intermediate table will contain the primary key for table 1 and the primary key for table 2.
In laravel, the convention for naming tables is plural for your main tables i.e. Community = 'communities' and Idea = 'ideas'. The pivot table name will be derived from the alphabetical order of the related model names i.e.
community_idea.
Now, if you don't want/can't to follow these conventions that's absolutely fine. For more information you can refer to the documentation: https://laravel.com/docs/5.2/eloquent-relationships#many-to-many
Once you're happy that you have the necessary tables with the necessary fields you can access the relationship by:
$ideas = $community->ideas()->get();
//or
$ideas = $community->ideas;
So you controller would look something like:
public function showCommunities($id)
{
$community = Community::findOrFail($id);
//The below isn't necessary as you're passing the Model to a view
// but it's good for self documentation
$community->load('ideas');
return view('publicPages.ideas_in_community', compact('community'));
}
Alternatively, you could add the ideas to the array of data passed to the view to be a bit more verbose:
public function showCommunities($id)
{
$community = Community::findOrFail($id);
$ideas = $community->ideas
return view('publicPages.ideas_in_community', compact('community', 'ideas));
}
Hope this helps!
UPDATE
I would imagine the reason that you're receiving the App\idea not found is because the model names don't match. It's good practice (and in certain environments essential) to Capitalise you class names so make sure of the following:
Your class name is Idea and it's file is called Idea.php
The class has it's namespace declared i.e. namespace App;
If you've added a new class and it's not being found you might need to run composer dump-autoload from the command line to update the autoloader.

How can I instantiate a new hasMany Eloquent relationship with at least one empty model?

I have a model (let's call it PageModel) with a hasMany relationship (let's call it rulesList). When I create a new PageModel, I want to default rulesList with at least one empty model. How can I do this in Eloquent?
Code Sample:
// Normal instantiation
$this->rulesList; // Equals NULL
// I can set it manually like so, but is that right?
$this->rulesList = Collection::make([new RulesListModel]);
// NOTE: Doing this does not create an empty model when PageModel is output as JSON
There isn't (to my knowledge) a way to do this within the relationship itself. The reason is that an eloquent model is defined by the database query return values.
You could set up some sort of null row in your database, but I would advise against that.
One way that may work: I think it is possible to create an eloquent model without running a query. I think something like EloquentModel::fill($attributes) would do it. Where $attributes is an array of attributes for your model e.g. array('title' => null, 'description' => null);
You'd have to create this manual model and then add it to your relationship.

How to make models use defaults in Phalcon PHP Framework?

If a table has defaults on certain fields and NULL is not allowed, one would expect the insert script to use those defaults, as MariaDB/MySQL usually does. For example, if the table products has an AI field "id", a required field "name" and two required fields "active" and "featured" which both default to 1, then the query
INSERT INTO products (name) VALUES ('someName');
automatically inserts 1 as the value of active and featured. However, when using Phalcon's models like so:
$product = new Products();
$product->setName('someName');
$product->save();
returns validation errors saying "active" and "featured" are required.
Is there a flag I should provide during model generation in order for Phalcon tools to harvest and input the defaults into Model classes, or another way to make Phalcon automatically use defaults if found? Best approach would be just ignoring the fields that weren't set, I reckon. Can I make the models do that?
You can use a raw database value to avoid that, in specific inserts:
<?php
use Phalcon\Db\RawValue;
$product = new Products();
$product->setName('someName');
$product->setType(new RawValue('default')); //use default here
$product->save();
Or, general before create/update for specific fields:
use Phalcon\Db\RawValue;
class Products extends Phalcon\Mvc\Model
{
public function beforeValidationOnCreate()
{
$this->type = new RawValue('default');
}
}
Or ignore these fields in every SQL INSERT generated:
use Phalcon\Db\RawValue;
class Products extends Phalcon\Mvc\Model
{
public function initialize()
{
$this->skipAttributesOnCreate(array('type'));
}
}
Although I find twistedxtra's answer fascinating from the aspect that Phalcon contains this wicked method to read the column default, I believe from a architectural point of view this might be the wrong approach as you rely on your database to define the defaults of the properties of your model.
I would set the default value when declaring the property and keep the logic in the application layer. But that's just me.
Use Like below
The skipAttributesOnCreate will make sure Phalcon does not attempt to put a a value in that column. The database will apply the default value.
public function initialize()
{
$this->setSource('table_name');
$this->skipAttributesOnCreate(['name_of_column']);
}

Removing a Table From CakePHP

I am trying to remove a table from CakePHP. All the tables were created with the cake bake function and I have removed the table from all the models. But when I remove the table from the database I get an error message:
Error: Database table channels_offers for model ChannelsOffer was not found.
Notice: If you want to customize this error message, create app/views/errors/missing_table.ctp
So how do I remove a table that was originally baked in?
Well, it appears that you still have a model called ChannelsOffer. You would need to add a property to your ChannelsOffer model. Here's an example
class ChannelsOffer extends AppModel {
// this tells the model not to use a table, alternatively you could supply your
// own table name here.
public $useTable = false;

Categories