Modify data before pagination in CakePhp - php

I'm trying to create an Api using cakephp.
I generate a json on server and it works fine , but I tired to use pagination and I got a problem.
in the first case I take the image's path and I encode it to base64 and I generate json => works
in the second case I defined the pagination by the limits and the max and I kept the same code but as a result the image field is still the path from the database and it's not encoded
this my code in my controller :
class PilotsController extends AppController {
public $paginate = [
'page' => 1,
'limit' => 5,
'maxLimit' => 5
];
public function initialize() {
parent::initialize();
$this->loadComponent('Paginator');
$this->Auth->allow(['add','edit','delete','view','count']);
}
public function view($id) {
$pilot = $this->Pilots->find()->where(['Pilots.account_id' => $id], [
'contain' => ['Accounts', 'Pilotlogs']
]);
foreach ($pilot as $obj) {
if ($obj->image_pilot!= NULL) {
$image1 = file_get_contents(WWW_ROOT.$obj->image_pilot);
$obj->image_pilot = base64_encode($image1);
}
}
$this->set('pilot', $this->paginate($pilot));
$this->set('_serialize', ['pilot']);
}
}
If I remove the pagination from the code it works fine . Any idea how to fix it ??

I'd suggest to use a result formatter instead, ie Query::formatResults().
So you'll have something like this :
public function view($id) {
$pilot = $this->Pilots->find()
->where(['Pilots.account_id' => $id], [
'contain' => ['Accounts', 'Pilotlogs']]);
->formatResults(function($results) {
return $results->map(function($row) {
$image1 = file_get_contents(WWW_ROOT.$row['image_pilot']);
$row['image_pilot'] = base64_encode($image1);
return $row;
});
});
}

You can simply first paginate the data and then get the array values and after that modify that data as you want. Check this
public function view($id) {
$pilot = $this->Pilots->find()->where(['Pilots.account_id' => $id], [
'contain' => ['Accounts', 'Pilotlogs']
]);
$pilot = $this->paginate($pilot);
$pilot = $pilot->toArray();
foreach ($pilot as $obj) {
if ($obj->image_pilot!= NULL) {
$image1 = file_get_contents(WWW_ROOT.$obj->image_pilot);
$obj->image_pilot = base64_encode($image1);
}
}
$this->set('pilot', $pilot);
$this->set('_serialize', ['pilot']);
}

Related

How to create a function in controller and use it in template/view in cakephp 3.xxx

I need to use the function in my view/template page.
My code:
public function getAppNumber($id = null){
$aPPLICATIONINFO = $this->AppEstLto->APPLICATIONINFO->find('all', [
'fields'=>['application_number'],
'conditions'=>['application_id'=>$id],
'limit' => 200
]);
foreach($aPPLICATIONINFO as $aPPLICATIONINFO){
$aPPLICATIONINFOx = $aPPLICATIONINFO;
}
return $aPPLICATIONINFOx;
}
You can use set() to use the function variables in your view as given in cookbook:https://book.cakephp.org/3/en/views.html#setting-view-variables
public function get_app_number($id = null){
$applicationInfo = $this->AppEstLto->APPLICATIONINFO->find('all',
[
'fields'=>['application_number'],
'conditions'=>['application_id'=>$id],
'limit' => 200
]);
//Create an array
$applicationArray = new array();
//Store all results in array
foreach($applicationInfo as $application){
$applicationArray = $application;
}
// Pass the array to view
$this->set(compact('applicationArray'));
}
Now, you can use it in your view:
get_app_number.ctp:
<?php
foreach($applicationArray as $application)
{
echo $application['application_number'];
}
?>
You should be doing something like this in your routes.php file inside your Config folder:
Router::connect('/get-app-number', array('controller' => 'yourController', 'action' => 'get_app_number'));
That way you will be able to connect the url that will be used for your view.
Your action corresponds and sends data to your view.
The action is the function that is inside your controller in which you developed for setting the data and variables.
The example of the slug which would be generated:
http://localhost/get-app-number

Category isn't getting related video blogs?

I am trying to get category related video blogs by below code but i get nothing in var_dump? I want to get category related videos:
$category = VideoBlogCategoryModel::findFirst(1); // This returns category successfully and there are many video blogs having this category linked
var_dump($category->getVideoBlogs());exit;
VideoBlogModel.php
public function initialize(){
// Run base initialize code
parent::initialize();
// Configure Relation with VideoBlogCategoryModel
$this->belongsTo('category_id', VideoBlogCategoryModel::class, 'id', array(
'alias' => 'videoCategory',
'foreignKey' => true
));
}
public function getVideoCategory(){
return $this->videoCategory;
}
public function setVideoCategory($videoCategory){
$this->videoCategory = $videoCategory;
}
VideoBlogCategoryModel.php
public function initialize(){
// Run base initialize code
parent::initialize();
// Configure relation with VideoBlogModel
$this->hasMany('id', VideoBlogModel::class, 'category_id', array(
'alias' => 'videoBlogs',
'foreignKey' => true,
'cxAction' => static::ACTION_CASCADE_DELETE
));
}
public function getVideoBlogs(){
return $this->videoBlogs;
}
public function setVideoBlogs($videoBlogs){
$this->videoBlogs = $videoBlogs;
}
Let me know if anything else is required, I will share it.
In VideoBlogCategoryModel.php change
public function getVideoBlogs() {
return $this->videoBlogs;
}
to
public function getVideoBlogs() {
return $this->getRelated('videoBlogs');
}
Then try accessing it like:
$category = VideoBlogCategoryModel::findFirst(1);
$videos = $category->getVideoBlogs();
foreach( $videos as $video ) {
// access data here
var_dump($video->anyProperty()); // e.g $video->getId()
}
can you try it
$category = VideoBlogCategoryModel::findFirst(1);
$videos = $category->getVideoBlogs();
var_dump($videos->count());
var_dump($videos->toArray());
exit;
I think use var_dump for a Phalcon Collection Object is not a good idea, you can convert it to Array and Var_dump
Hope it can help you
Or try:
$categories = VideoBlogCategoryModel::findById($id);

YIi PHP - Output array with a foreach loop

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;
}

Laravel and a While Loop

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.

Cluttered Controllers in Laravel 5.1

Is there a better way of organizing or writing the below controller method in Laravel 5.1?
I want to keep my Controllers short and sweet. I am using a repository setup as i'm building quite a large application and I want to keep everything organised.
Please advise on the best way to organise the below code.
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create(CreateTimesheetRequest $request)
{
$data = $request->only('user_id', 'template_id');
$data['submitted_by'] = Auth::user()->id;
$timesheetId = $this->timesheet->createTimesheet($data);
foreach($request->get('row') as $key => $row)
{
foreach($row as $field => $value)
{
$this->timesheet->saveTimesheetRows([
'timesheet_id' => $timesheetId,
'field_id' => $this->timesheetFields->where('name', $field)->first()->id,
'field_name' => $field,
'field_value' => $value,
'field_key' => $key
]);
}
}
return Redirect::back()->withMessage('The timesheet was successfully created.');
}
All I can suggest - move this:
$data = $request->only('user_id', 'template_id');
$data['submitted_by'] = Auth::user()->id;
... into yours request class. For example, into some data() method:
class CreateTimesheetRequest ... {
...
public function data() {
return array_merge(
$this->only('user_id', 'template_id'),
['submitted_by' => Auth::user()->id]
);
}
}
Also, $this->timesheet->saveTimesheetRows(array) looks more like $this->timesheet->saveTimesheetRow(array) for me - name intends to save multiple rows, but you feed that method only with one row per call.
Maybe, you can refactor that method to smth. like this:
function saveTimesheetRows($timesheetId, $key, $rows, $fieldIds) {
foreach($rows as $field => $value) {
$this->saveTimesheetRow([
'timesheet_id' => $timesheetId,
'field_id' => $fieldIds[$field],
'field_name' => $field,
'field_value' => $value,
'field_key' => $key
]);
}
}
function saveTimesheetRow(array $row) {
// old saveTimesheetRows implementation
}
Upd.
And another tip: use Eloquent's keyBy() method like so:
$keyIDs = $this->timesheetFields->whereIn('name', $fields)->get(["name", "id"])->keyBy("name");
So, finally:
public function create(CreateTimesheetRequest $request) {
$data = $request->data();
$timesheetId = $this->timesheet->createTimesheet($data);
foreach($request->get('row') as $key => $row) {
$this->timesheet->saveTimesheetRows(
$timesheetId,
$key,
$row,
$this->timesheetFields
->whereIn('name', array_keys($row))
->get(["name", "id"])
->keyBy("name") // probably, can be moved into $this->timesheetFields implementation
);
}
return Redirect::back()->withMessage('The timesheet was successfully created.');
}

Categories