I have a JavaScript based page where a grid displays all the data for the registered users which is taken from the database.In the UI I have also column named 'groups' which display the groups that every users is participating, but this info is taken using additional two additional tables - 'groups' with 'id' and 'group_name' as columns, and a table 'users_groups' which has 'user_id' and 'group_id' as columns which are foreign keys associated with 'users' and 'groups' tables.
The problem is that when you click to edit any user from the UI grid there an AJAX that post JSON to containing the information for the user which include the
'groups' column which actually is not part of the 'users' table. So I have this:
$data = json_decode($this->input->post('data'), true);
Which originally (when the groups weren't added yet) was transformed in this:
$data = array(
'id' => $data['id'],
'email' => $data['email'],
'firstname' => $data['firstname'],
'lastname' => $data['lastname'],
'usertype' => $data['usertype']
);
And then parsed to the model named 'mUsers' where is the update function:
$query = $this->mUsers->update($data);
And the model since now was very simple because there was only one table:
public function update($data)
{
$this->db->where('id', $data['id']);
$query = $this->db->update('users', $data);
return true;
}
But now I have to update another table - 'users_groups' and I'm thinking about my options.Is it possible to just add to the $data array show above another record:
'groups' => $data['groups']
And try to implement all the logic in one function(If this even possible, I couldn't find info if I can have two different active record queries in one function) or the second thing I thought of was after decoding the JSON to make something like:
$dataGroups = array(
'groups' => $data['groups'] //adding groups data to be fetched for update
);
and then parsing the data to a new function, something like:
$q = $this->mUsers->updateGroups($dataGroups);
What would be the better approach in this case?
Thanks
Leron
Make both function. And call them when necessary also you will be able to to call only usergroup function alone
//this function update all user data including group
public function updateUser($data, $changeGroup = true)
{
$this->db->where('id', $data['id']);
$query = $this->db->update('users', $data);
if($changeGroup) {
$this->updateUserGroup($data['id'], $data['groups']);
}
}
//Update user group
public function updateUserGroup($userid, $usergroups)
{
//Update user groups
}
Related
i have admin list and member list which i have categorize by 'a' and 'm'. Now i am showing admin lists and member lists in different tabs. Now problem is if a user is in member list and is logged in than his name should not shown in member list.
Here is the controller:
public function view_customer(){
$data = json_decode(file_get_contents('php://input'));
$customers=$this->um->view_customers();
header("Content-Type: application/json; charset=UTF-8");
echo json_encode($customers);
}
Here is the model:
public function view_customers(){
$this->db->select('reg_id,reg_name,email,user_type,pic_url,id,name,cover_image,restaurant_id');
$this->db->from('registration');
$this->db->where('user_type','m');
$this->db->join('rest_restaurant_master','registration.restaurant_id=rest_restaurant_master.id','inner');
$query=$this->db->get()->result_array();
return $query;
}
Basically you need a variable that is both contained in your table, and is related to the user. I'm assuming you have one called id that relates to a session variable called user_id.
Add to view_customers:
$this->db->where_not_in('id', $this->session->user_id);
Or (easier):
$this->db->where('id !=', $this->session->user_id);
This way your array will contain users who are only in m and who are not the active user.
When you set session (in login)
$newdata = array(
'id' => 3, # id is database user recorded id
'username' => 'johndoe',
'email' => 'johndoe#some-site.com',
'logged_in' => TRUE
);
$this->session->set_userdata($newdata);
and then in all the method you can call
$loggedUser = $this->session->id; # or $this->session->userdata('id');
$this->db->where_not_in('id', $loggedUser);
Read this Session Library class
I have the registered Comment model which has a User reference, like this:
public function user() {
return $this->belongsTo('App\User');
}
This function returns an instance of a User, and that's correct, but I don't know how to register the User column the get que user property using Backpack. Instead, I'm get a JSON representation of my model:
So, how do I get a specific field from my relationship function?
Sounds like the select column is a perfect match for you. Just use it in your EntityCrudController's setup() method, like so:
$this->crud->addColumn([
// 1-n relationship
'label' => "User", // Table column heading
'type' => "select",
'name' => 'user_id', // the column that contains the ID of that connected entity;
'entity' => 'user', // the method that defines the relationship in your Model
'attribute' => "user", // foreign key attribute that is shown to user
'model' => "App\Models\User", // foreign key model
]);
The "attribute" tells CRUD what to show in the table cell (the name, the id, etc).
If you do:
$user = $comment->user->user;
You'll get 'test'; (from your example)
It may seem confusing because your User model has a user attribute. Maybe you can call it 'name' instead of 'user'. That way you'll call it:
$username = $comment->user->name;
Remember to check if the relationship exists before calling a property on the related model.
if(!is_null($comment->user)) {
$username = $comment->user->user;
}
Or:
$username = !is_null($comment->user) ? $comment->user->user : 'No user';
If you need to get some field from deeper relation, you can use closure column type:
$this->crud->addColumn([
'label' => trans('backend.column_names.agency_linked_service'),
'name' => 'agency_service_id',
'type' => 'closure',
'function' => function (AgencyLinkedServices $entry) {
return $entry->agencyService->agencyCategory->title;
}
]);
Plugin: FriendsOfCake/Search
CakePHP: 3.1.4
I'm using the plugin to filter my index.ctp view data with a form.
This similar question:
How to Filter on Associated Data
is about a belongsTo association. My question is specifically about associated HABTM data where my associated table is linked through a joinTable and not directly. The normal setup in the Model like the following is not working in this case:
->value('painting', [
field' => $this->Paintings->target()->aliasField('id')
)]
My tables are set up like:
Tickets belongsToMany Paintings
Paintings belongsToMany Tickets
with joinTable tickets_paintings
Here is the main setup:
class TicketsTable extends Table
{
public function initialize(array $config)
{
...
$this->belongsToMany('Paintings', [
'foreignKey' => 'ticket_id',
'targetForeignKey' => 'painting_id',
'joinTable' => 'tickets_paintings'
]);
}
public function searchConfiguration()
{
$search = new Manager($this);
$search->value('status', [
'field' => $this->aliasField('active'),
])->like('member_name', [
'field' => $this->Members->target()->aliasField('surname'),
'filterEmpty' => true
])->value('painting', [
'field' => $this->Paintings->target()->aliasField('id'), // not working
]);
return $search;
}
class TicketsController extends AppController
{
public function index()
{
$query = $this->Tickets
->find('search',
$this->Tickets->filterParams($this->request->query))
->contain(['Members', 'Paintings', 'Appointments']);
...
}
Everything else is working and the parameters are added to the URL when I filter etc., so I only put in the parts where sth has to be wrong.
After filtering I get an error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Paintings.id' in 'where clause'
The contain works properly when just displaying data from the Paintings table in the Tickets view.
But in the code from the SQL query I can see, that all contained tables (Members, Appoinments) are joined for the query except the Paintings table, so obviously it can not find the column...And I guess it can't really join it directly anyway since they are only connected through the joinTable.
I'm new to CakePHP and I can't really figure out what I'm doing wrong here, so hopefully someone can help me out a bit.
Do I have to use a different syntax in the plugin settings? Do I have to set up my Tables differently? Or how exactly can I tell the query to incorporate the habtm related table in the search?
Thanks!
The available search methods rely on the field being available in the main query (hasMany and belongsToMany associations are being being retrieved in separate queries).
While you could join it in manually in the controller, using a callback- or a finder-filter is probably the better approach, that way you can modify the query in the model layer, and you could easily utilize Query::matching() to filter by associated data.
Here's an (untested) example that should give you a hint:
use Cake\ORM\Query;
use Search\Type\Callback; // This changed in master recently
// now it's Search\Model\Filter\Callback
// ...
public function searchConfiguration()
{
$search = new Manager($this);
$search
// ...
->callback('painting', [
'callback' => function (Query $query, array $args, Callback $type) {
return $query
->distinct($this->aliasField('id'))
->matching('Paintings', function (Query $query) use ($args) {
return $query
->where([
$this->Paintings->target()->aliasField('id') => $args['painting']
]);
});
}
]);
return $search;
}
See also
https://github.com/FriendsOfCake/search/blob/9e12117404f824847b2d1aa093f3d52736b658b4/README.md#types
https://github.com/FriendsOfCake/search/blob/master/README.md#filters
Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Filtering by Associated Data
I have a table named 'Tbluser'. It contains 'company_code, user_code'.I can show this table using grid view.
i want to show only one specific company users. example, if a company_code: 'company1' logs in, he can only see user_code and company_code associated with company1.
How can i select only those attributes with 'company1'? Is there any function which provides all the attributes for a single column?
You will need to do this via the data provider for example
public function myDataProvider()
{
$id = Yii::app()->user->name;
$dataProvider=new CActiveDataProvider('MODELNAME', array(
'criteria'=>array(
'condition'=>'company_code= :id',
'params' => array(':id' => $id),
),
'pagination'=>array(
'pageSize'=>5,
),
));
return $dataProvider;
}
I presume that company1 is the users name. If not simply change it to say username/id etc.
Many thanks to Veelen for suggested edit (using params protects against sql injections).
I have 2 models: taxiDrivers and taxiOrders. In taxiOrders I have a field driver_id, but instead of just an id, I want to output driver's name (which is located in taxiDrivers). Both models are generated via gii, and crud tools are also generated. The page which is needed to be changed is taxiOrders/admin (view: admin.php, models: TaxiOrders.php, TaxiDrivers.php and respective controllers)
2 DCoder: Thanks dude! but one more query I have and hope you can clearify: I have a standart generated admin.php view page with following code:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'taxi-orders-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'id',
'uid',
'did',
'type',
'notes',
//'or_lat',
//'or_lng',
//'des_lat',
//'des_lng',
'cost',
'rating',
'date',
'time',
'status',
array(
'class'=>'CButtonColumn',
),
),
)); ?>
and below code is for controller:public function actionAdmin()
{
$model=new TaxiOrders('search');
$model->unsetAttributes(); // clear any default values
if(isset($_GET['TaxiOrders']))
$model->attributes=$_GET['TaxiOrders'];
$this->render('admin',array(
'model'=>$model,
));
}
So can u please show me where I could put your manipulations.
The Yii way would be to define a Relation between the two model classes (and enforce it with a Foreign Key). Then Yii would know how the two classes are related and you would have an easier time loading the related data.
In the TaxiOrders model class, a relation would look like this:
/**
* #property TaxiDrivers $Driver
*/
class TaxiOrders extends CActiveRecord {
// ...
public function relations() {
return array(
'Driver' => array(self::BELONGS_TO, 'TaxiDrivers', 'driver_id'),
);
}
// ...
}
In the controller, when you load the order data, you can prefetch the associated driver data like this:
public function actionOrderInfo($orderID) {
$order = TaxiOrders::model()->with('Driver')->findByPk($orderID);
// render it
}
with('Driver') will make sure that each returned order has its driver info already loaded, no matter if you need to find one record or a lot of records. It is a lot more efficient than trying to load that related data yourself.
In the view, you can output the driver info like this:
echo CHtml::encode($order->Driver->Name);
Unless you have a foreign key to ensure data integrity, it is possible that the Driver has been deleted without clearing his existing orders... In that case $order->Driver will be NULL and the line above will cause an error. Figuring out how to avoid it should be obvious.
In TaxiOrders admin use this to display driver name
TaxiDrivers::getName($data->driver_id);
Now in the TaxiDrivers Model write a function with sql query to get the driver name like this...
public function getName($getid) {
$sql = "SELECT name from `taxi_drivers` where `driver_id`='$getid'";
$command=yii::app()->db->createCommand($sql);
$rs = $command->queryScalar();
return $rs;
}
I Hope it will help you..
I always prefer Query Builder approach instead of Active record approach in joined scenarios. Like that
First Get Data through Query Builder
public function getTaxtOrder($id) {
$select = Yii::app()->db->createCommand()
->select('to.*, td.name as driver_name')
->from('TaxiOrders to')
->join('TaxiDriver td', 'td.id = to.driver_id')
->where('to.id = :id', array(':id' => $id));
return $select->queryRow();
}
Then Pass through controller
$data = TaxiOrders::model()->getTaxtOrder($id);
$this->render('view',array(
'data' => $data
));
Last use this into views
$this->widget('zii.widgets.CDetailView', array(
'data'=>$data,
'attributes'=>array(
array('label' => 'Order No', 'value' =>$model['order_no']),
array('label' => 'Driver Name', 'value' =>$model['driver_name']),
array('label' => 'Date', 'value' =>$model['order_date']),
),
));
This approach easily and flexibly work with multiple joined tables than Active Record Approach.