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.
Related
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 have the following method in a controller
public function artikel(){
$breadcrumb = array(
'Home' => URL::to('/'),
'Artikel' => ''
);
$this->layout->title = "Egoji";
$artikels = Posting::orderBy("created_at","desc")->where("postings.tipe","=","artikel")->paginate(5);
$this->layout->content = View::make("frontend.artikel.index",array("artikels"=>$artikels, 'breadcrumb'=>$breadcrumb))->render();
}
in the view frontend.artikel.index i am trying to takeout first artikel using $artikels->shift(). i get the first artikel, but it doesnt remove from the collection, it still there when i loop the rest.
I have a controller, that doesn't render a view (the file is present). It just simply shows a blank page.
Also it happens only on staging server - two other dev environments work fine.
Here's the code:
function category($catId = null)
{
if (!isset($catId) || empty($catId)) {
$this->data['category'] = 'all';
$this->data['categories'] = $this->ShopCat->find('all',array('order'=>array('ShopCat.title ASC')));
$this->paginate = array(
'limit' => 9,
'order' => array('ShopProd.featured DESC','ShopProd.title ASC')
);
$this->data['products'] = $this->paginate('ShopProd');
} else {
$catId = (int) $catId;
$this->ShopCat->id = $catId;
if (!$this->ShopCat->exists($catId)) $this->cakeError('error404');
$this->data['category'] = $this->ShopCat->find('first', array('ShopCat.id' => $catId));
$this->data['categories'] = $this->ShopCat->find('all',array('order'=>array('ShopCat.title ASC')));
$this->paginate = array(
'conditions' => array('ShopProd.shop_cat_id' => $catId),
'limit' => 9
);
$this->data['products'] = $this->paginate('ShopProd');
}
}
Why isn't this working? Cause I have no ideas ...
UPDATE : the whole controller code runs ok, it just simply doesn't render anything. In other controller methods - all fine, works perfectly.
UPDATE : issue resolved, thanks to everyone :) it was an error in a view file.
Your $catId will always exist. You have declared in the function.
Maybe is more useful updated your first if to
if (empty($catId)) {...}
Do you have imported the another model in your controller?
Like: $uses = array('ShopCat', 'ShopProd');
or use App::import('Model', 'ShopCat') before $this->find
Figured it out - there was an error in a view file.
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