PlanDetails hasMany Companies. PlanDetail table has company_id field.
This is all I need to achieve: PlanDetail.company_id = Company.id. So get all Plan Details where PlanDetail.company_id matches Company.id.
Here is the query I have been messing with in the plan_details_controller:
function pd_list_by_company() {
$this->PlanDetail->unbindModel(array('hasMany' => array('Plan')));
$comp_id = $this->PlanDetail->Company->find('all');
$result = $this->PlanDetails->find('all', array('conditions' => array
('Company.id' => 'PlanDetail.company_id')));
$company_id = $this->PlanDetail->read('company_id');
}
I cannot just get the results I need.. what am I doing wrong here?
Sounds like a simple condition on the company_id field to me:
$this->PlanDetail->find('all', array('conditions' => array('company_id' => $company_id)))
Or, if you want the company as well and your associations are hooked up correctly:
$company = $this->Company->read(null, $company_id);
// echo $company['Company']
// echo $company['PlanDetail'][0], $company['PlanDetail'][1] etc...
You need to get a $company_id to query on from somewhere, which is usually the URL:
public function pd_list_by_company($company_id)
Then visit this action with the URL /plan_details/pd_list_by_company/42, which can be linked to using $this->Html->link('foobar', array('controller' => 'plan_details', 'action' => 'pd_list_by_company', 42)).
Complete example:
public function view($planId) {
$plan = $this->PlanDetail->read(null, $planId);
if (!$plan) {
$this->cakeError('error404');
}
$otherPlansBySameCompany = $this->PlanDetail->find('all', array(
'conditions' => array('company_id' => $plan['PlanDetail']['company_id'])
));
$this->set(compact('plan', 'otherPlansBySameCompany'));
}
I am displaying the set() find result in the Plan Detail view.ctp.
This is how I solved it:
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid plan detail', true));
$this->redirect(array('action' => 'index'));
}
$this->set('planDetail', $this->PlanDetail->read(null, $id));
$cid = $this->PlanDetail->read('Company.id');
$cid_extract = Set::extract($cid, 'Company.id');
$this->set('planComps', $this->PlanDetail->find('all',array('conditions' => array("company_id" => $cid_extract))));
}
Related
I'm trying to return a navigation menu using Yii PHP framework, but my controller is only outputting the first item in the array, here's my code. Note that this pattern isn't using the traditional MVC, the model i'm asking data for is being displayed site-wide, not directly to its's controller->view.
Model - get data;
//output pages for getPagesMenuItems() in base controller
public function getAllPages(){
$criteria = new CDbCriteria();
$criteria->condition = "visible = 1";
return Pages::model()->findAll($criteria);
}
Base controller in components
public $pagesMenuItems = array();
$this->pagesMenuItems = $this->getPagesMenuItems();
protected function getPagesMenuItems() {
//Non admin users - links to pages
if (Yii::app()->user->isGuest){
$rows = Pages::getAllPages();
foreach($rows as $row) {
return array(
//$row->id , $row->title , $row->guid , $row->visible
array('label' => $row->title, 'icon' => 'fa fa-times', 'url' => array('/admin/pages/view/id/' . $row->id)),
'---',
);
}
// return array();
}
else {}
}
And this is the view in the main.php
$this->widget('booster.widgets.TbMenu', array(
'items' => $this->pagesMenuItems,
'id' => 'pagesNav'
));
I know the issue is packaging the array in the foreach loop, as i've tested the output of the model and all data is correct
Can anyone see where i'm going wrong in my controller?
Thanks
change getPagesMenuItems function as below:
protected function getPagesMenuItems() {
//Non admin users - links to pages
$data = array();
if (Yii::app()->user->isGuest){
$rows = Pages::getAllPages();
foreach($rows as $row) {
$data[] = array('label' => $row->title, 'icon' => 'fa fa-times', 'url' => array('/admin/pages/view/id/' . $row->id));
}
}
else {}
return $data;
}
I'm new to Laravel and at the moment I have a piece of code in a Controller which without the while loop it works, it retrieves my query from the database.
public function dash($id, Request $request) {
$user = JWTAuth::parseToken()->authenticate();
$postdata = $request->except('token');
$q = DB::select('SELECT * FROM maps WHERE user_id = :id', ['id' => $id]);
if($q->num_rows > 0){
$check = true;
$maps = array();
while($row = mysqli_fetch_array($q)) {
$product = array(
'auth' => 1,
'id' => $row['id'],
'url' => $row['url'],
'locationData' => json_decode($row['locationData']),
'userData' => json_decode($row['userData']),
'visible' => $row['visible'],
'thedate' => $row['thedate']
);
array_push($maps, $product);
}
} else {
$check = false;
}
return response()->json($maps);
}
I am trying to loop through the returned data from $q and use json_decode on 2 key/val pairs but I can't even get this done right.
Don't use mysqli to iterate over the results (Laravel doesn't use mysqli). Results coming back from Laravel's query builder are Traversable, so you can simply use a foreach loop:
$q = DB::select('...');
foreach($q as $row) {
// ...
}
Each $row is going to be an object and not an array:
$product = array(
'auth' => 1,
'id' => $row->id,
'url' => $row->url,
'locationData' => json_decode($row->locationData),
'userData' => json_decode($row->userData),
'visible' => $row->visible,
'thedate' => $row->thedate
);
You're not using $postdata in that function so remove it.
Do not use mysqli in Laravel. Use models and/or the DB query functionality built in.
You're passing the wrong thing to mysqli_fetch_array. It's always returning a non-false value and that's why the loop never ends.
Why are you looping over the row data? Just return the query results-- they're already an array. If you want things like 'locationData' and 'userData' to be decoded JSON then use a model with methods to do this stuff for you. Remember, with MVC you should always put anything data related into models.
So a better way to do this is with Laravel models and relationships:
// put this with the rest of your models
// User.php
class User extends Model
{
function maps ()
{
return $this->hasMany ('App\Map');
}
}
// Maps.php
class Map extends Model
{
// you're not using this right now, but in case your view needs to get
// this stuff you can use these functions
function getLocationData ()
{
return json_decode ($this->locationData);
}
function getUserData ()
{
return json_decode ($this->userData);
}
}
// now in your controller:
public function dash ($id, Request $request) {
// $user should now be an instance of the User model
$user = JWTAuth::parseToken()->authenticate();
// don't use raw SQL if at all possible
//$q = DB::select('SELECT * FROM maps WHERE user_id = :id', ['id' => $id]);
// notice that User has a relationship to Maps defined!
// and it's a has-many relationship so maps() returns an array
// of Map models
$maps = $user->maps ();
return response()->json($maps);
}
You can loop over $q using a foreach:
foreach ($q as $row) {
// Do work here
}
See the Laravel docs for more information.
i am developing with cakephp (2.4.7) and i have problems with organizing my controllers and models to use pagination.
So far i put the most logic into the models (thin controller, big model). There i returned the results to the controller where i set the variables to display it on the view.
But now i want to use pagination. This break my concept because i can not use pagination inside the models.
Whats the best solution to solve this problem? I do not want to reorganzie my whole structure, because i need pagination in a lot of different actions and models.
For example:
Controller Users, action friends
public function friends($userid = null, $slug = null) {
$this->layout = 'userprofile';
$this->User->id = $userid;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid User'));
}
$this->set('friends', $this->User->getFriendsFrom($userid));
}
User Model, function getFriendsFrom($user_from).. i need this method in different actions.
public function getFriendsFrom($user_from) {
$idToFind = $user_from;
$data = $this->FriendFrom->find('all',
array(
'conditions'=>array(
'OR'=> array(
array('user_to'=> $idToFind),
array('user_from'=> $idToFind)
),
'AND' => array(
'friendship_status' => 1
)
),
'contain' => array('UserFrom.Picture', 'UserTo.Picture')
)
);
$friendslist = array();
foreach ($data as $i) {
if ($i['FriendFrom']['user_from'] == $idToFind){
$friendslist[] = $i['UserTo'];
}
elseif ($i['FriendFrom']['user_to'] == $idToFind){
$friendslist[] = $i['UserFrom'];
}
}
return $friendslist;
}
Whats the best way to design this concept to use pagination?
Thanks
in Controller Users use cakephp Paginator
var $helpers = array('Paginator');
Now you call the following method
function index() {
$result = array(
'recursive' => -1,
'conditions' => array(...),
'contain' => array(...),
'limit' => '2'
);
// you can write the above code in your model
$this->paginate = $result;
$users = $this->paginate('User');
// Re-arrage $users
$this->set(compact('users'));
}
If any problem, let me know.
I'm setting up pagination to display a list of images belonging to the user in their account. This is what I have in my controller:
class UsersController extends AppController {
public $paginate = array(
'limit' => 5,
'order' => array(
'Image.uploaded' => 'DESC'
)
);
// ...
public function images() {
$this->set('title_for_layout', 'Your images');
$albums = $this->Album->find('all', array(
'conditions' => array('Album.user_id' => $this->Auth->user('id'))
));
$this->set('albums', $albums);
// Grab the users images
$options['userID'] = $this->Auth->user('id');
$images = $this->paginate('Image');
$this->set('images', $images);
}
// ...
}
It works, but before I implemented this pagination I had a custom method in my Image model to grab the users images. Here it is:
public function getImages($options) {
$params = array('conditions' => array());
// Specific user
if (!empty($options['userID'])) {
array_push($params['conditions'], array('Image.user_id' => $options['userID']));
}
// Specific album
if (!empty($options['albumHash'])) {
array_push($params['conditions'], array('Album.hash' => $options['albumHash']));
}
// Order of images
$params['order'] = 'Image.uploaded DESC';
if (!empty($options['order'])) {
$params['order'] = $options['order'];
}
return $this->find('all', $params);
}
Is there a way I can use this getImages() method instead of the default paginate()? The closest thing I can find in the documentation is "Custom Query Pagination" but I don't want to write my own queries, I just want to use the getImages() method. Hopefully I can do that.
Cheers.
Yes.
//controller
$opts['userID'] = $this->Auth->user('id');
$opts['paginate'] = true;
$paginateOpts = $this->Image->getImages($opts);
$this->paginate = $paginateOpts;
$images = $this->paginate('Image');
//model
if(!empty($opts['paginate'])) {
return $params;
} else {
return $this->find('all', $params);
}
Explanation:
Basically, you just add another parameter (I usually just call it "paginate"), and if it's true in the model, instead of passing back the results of the find, you pass back your dynamically created parameters - which you then use to do the paginate in the controller.
This lets you continue to keep all your model/database logic within the model, and just utilize the controller to do the pagination after the model builds all the complicated parameters based on the options you send it.
How can I pass the model in array format.
I want to pass models in this format from controller to view:-
Users[user_contact]=Contact
Users[user_contact][contat_city]=City
Users[user_contact][contact_state]=state
This is what I am doing
public function actionCreate() {
$user = new Users;
$presContact = new Contacts;
$presCity = new Cities;
$presState = new States;
$contactArr = array();
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if (isset($_POST['Users'])) {
$transaction = CActiveRecord::getDBConnection()->beginTransaction();
$contactArr = CommonFunctions::saveContact($_POST['Users']['user_pres_contact'],'user_pres_contact',$errorArr);
$presContact = $contactArr['contact'];
$presCity = $contactArr['city'];
$presState = $contactArr['state'];
$user->attributes = $_POST['Users'];
$user->user_pres_contact_id = $presContact->contact_id;
if($user->save()){
$transaction->commit();
$this->redirect(array('view', 'id' => $user->user_id));
} else {
$transaction->rollback();
}
}
$this->render('createUser', array(
'Users' => $user,
'Users[\'user_pres_contact\']'=>$presContact,
'Users[\'user_pres_contact\'][\'contact_city\']'=>$presCity,
'Users[\'user_pres_contact\'][\'contact_state\']'=>$presState,
));
}
I am able to access only $users but
I m not able to access $Users['user_pres_contact'] in the view
That's because you are assigning them as strings...
The correct way of doing things would be (btw, what you are asking for can't done literally, it is impossible to assign 2 values to one key):
$user = array(
'user_press_contact' => array(
'contact' => $presContact,
'city' => $presCity,
'state' => $presState,
),
);
$this->render('createUser', array(
'Users' => $user,
));
It will give you $Users['user_press_contact']['contact'] for the name in the view, etc.
You can use
$user->getAttributes() //it returns an array of data.
Hope that's usefull
It is possible to solve this using model relations? You can define a relation from the User model to the City model (e.g. naming it relation_to_city), then you can just assign the user model in the controller
$this->render('view', 'user'=>$user);
and access the city (from the view)
$user->relation_to_city