I am using FullCalendar , its work perfectly , but i need to add href to the button className='btn' when i click on redirect to view page .
my code in controller :
public function actionIndex()
{
$events = event::find()->all();
$taskes=[];
foreach ($events as $eve)
{
$event1 = new \yii2fullcalendar\models\Event();
$patient = patient::findOne($eve->patient_id);
$event1->className='btn'; // this button that i need to add link to : ['site/view', 'id' => $id ]
$event1->id = $eve->id;
$event1->title = $patient->patient_name;
$event1->start = $eve->event_date;
$taskes[] = $event1;
}
return $this->render('index', [
'events'=>$taskes,
]);
}
I think you can make like this:
...
$event1->url = Url::to(['site/view', 'id' => $id ]);
...
Look in the documentation - http://fullcalendar.io/docs/event_data/Event_Object/
Related
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']);
}
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 set up editable column for the GridView in Yii2 with Kartik Editable extension. The problem I am facing is that I cannot find a way to update multiple table cell from one editable column.
The things I did:
GridView column
[
'class' => 'kartik\grid\EditableColumn',
'attribute'=>'post_title',
'editableOptions'=> function ($model, $key, $index) {
return [
'inputType' => \kartik\editable\Editable::INPUT_TEXT,
'size'=>'sm',
'afterInput'=>function ($form, $widget) use ($model, $index) {
return $form->field($model, 'post_description')->textInput(['placeholder'=>'Enter post title']);
}
];
}
],
By clicking edit post title column it shows edit fields for title and description
PostsController action
public function actionIndex()
{
$searchModel = new PostsSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
if (Yii::$app->request->post('hasEditable')) {
$postId = Yii::$app->request->post('editableKey');
$model = Posts::findOne($postId);
$out = Json::encode(['output'=>'', 'message'=>'']);
$post = [];
$posted = current($_POST['Posts']);
$post['Posts'] = $posted;
if ($model->load($post)) {
$output = '';
$out = Json::encode(['output'=>$output, 'message'=>'']);
$model->save();
}
echo $out;
return;
}
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
So, when I edit post title and description only post title is saved into database.
I think it is because current saves only one value
$posted = current($_POST['Posts']);
What is the proper way to save both
$model->post_title and $model->post_description ?
This is an Ajax editable column. At a time only one value would be sent to the controller.
So the class of post_title and post_description column must be editable in the view.
This should work everytime you edit those columns.
Also change this
if ($model->load($post)) {
if (isset($model->post_title)){
// here you can format the value of the attribute
and display on the screen
$output = $model->post_title;
}
if (isset($model->post_description)){
$output = $model->post_description;
}
$model->save();
// Here you send a message that the value has been saved
$out = Json::encode(['output'=>$output, 'message'=>'Saved']);
}
I am building a simple mechanism where a user can like a post by clicking on a link. I'm using GET rather than POST as I want to allow the method to fire via the URL.
That been said how do I save data using GET? As the request data doesn't exist in this scenario... My model looks like:
class Like extends AppModel
{
public $name = 'Like';
public $belongsTo = array('User','Post');
}
and the method for adding looks like:
public function add( $id )
{
$post = $this->Post->find('first', array(
'conditions' => array('Post.id'=>Tiny::reverseTiny($id))
));
if (!$post)
{
throw new NotFoundException('404');
}
if($post['Post']['user_id'] == $this->Auth->user('id'))
{
$this->Session->setFlash('You can\'t like your own post... That\'s just silly!');
}
if ($this->Like->create())
{
$liked = $this->Like->find('first', array(
'conditions' => array('Like.id'=>Tiny::reverseTiny($id), 'Like.user_id'=>$this->Auth->user('id') )
));
if(!$liked){
$this->Like->saveField('user_id', $this->Auth->user('id'));
$this->Like->saveField('post_id', $post['Post']['id']);
$this->redirect(array('controller'=>'posts','action'=>'view','id'=>Tiny::toTiny($post['Post']['id']),'slug'=>$post['Post']['slug']));
} else {
$this->Session->setFlash('You already like this post!');
}
else
{
$this->Session->setFlash('Server broke!');
}
}
Can anyone help?
<?php echo $this->Html->link('1', array('controller'=>'followers','action'=>'add','id'=>Tiny::toTiny($post['Post']['id'])),
array('title'=>'Follow','class'=>'follow')); ?>
This part all works fine. It's saving a new row in the DB on GET that I'm struggling with.
Hi you just need to make a link to your controller action and pass you variable in the url.
to be clear the link on the post to like is in your post view :
$this->Html->link('like this post', array('controller' => 'like', 'action' => 'add', $postId))
It should render a link like this :
www.yourWebSite/likes/add/1 to like the postId 1,
variables after your action (add) are interpreted as variable for your controller action
if your fonction add had been
public function add($postId, $wathever){
}
the url should look like www.yourWebSite/likes/add/1/blabla
where 1 is the first var for the add action and blabla the second one and so on.
this is the equivalent of a non rewriting url : ?postId=1&whatever=blabla
EDIT :
if(!$liked){
//simulate the post behaviour
$this->request->data['Like']['user_id'] = $this->Auth->user('id');
$this->request->data['Like']['post_id'] = $post['Post']['id'];
//save the data
if ($this->Like->save($this->request->data)) {
$this->Session->setFlash(__('Thanks for your support !'));
$this->redirect(array('controller'=>'posts','action'=>'view','id'=>Tiny::toTiny($post['Post']['id']),'slug'=>$post['Post']['slug']));
} else {
$this->Session->setFlash('Server broke!');
}
}
How about using save with id=0 instead of create?
<?php
$like = array(
"Like" => array
(
"id" => 0,
"user_id" => $this->Auth->user("id"),
"post_id" => $post['Post']['id']
)
);
$result = $this->Like->save($like);
if(!$result){$this->Session->setFlash('Server broke!');}
$this->redirect(array('controller'=>'posts','action'=>'view','id'=>Tiny::toTiny($post['Post']['id']),'slug'=>$post['Post']['slug']));
?>
I need next & previous id record in database on Yii framework to make navigation buttons next and back ?
I added following functions in my model in Yii2:
public function getNext() {
$next = $this->find()->where(['>', 'id', $this->id])->one();
return $next;
}
public function getPrev() {
$prev = $this->find()->where(['<', 'id', $this->id])->orderBy('id desc')->one();
return $prev;
}
I made a function to get those ids your looking for. I suggest you to declare it in the model:
public static function getNextOrPrevId($currentId, $nextOrPrev)
{
$records=NULL;
if($nextOrPrev == "prev")
$order="id DESC";
if($nextOrPrev == "next")
$order="id ASC";
$records=YourModel::model()->findAll(
array('select'=>'id', 'order'=>$order)
);
foreach($records as $i=>$r)
if($r->id == $currentId)
return isset($records[$i+1]->id) ? $records[$i+1]->id : NULL;
return NULL;
}
So to use it all you have to do do is this:
YourModel::getNextOrPrevId($id /*(current id)*/, "prev" /*(or "next")*/);
It will return the corresponding id of the next or previous record.
I didn't test it, so give it a try and if something goes wrong please let me know.
Make a private var that is used to pass info to other functions.
In Model:
class Model1 .....
{
...
private _prevId = null;
private _nextId = null;
...
public function afterFind() //this function will be called after your every find call
{
//find/calculate/set $this->_prevId;
//find/calculate/set $this->_nextId;
}
public function getPrevId() {
return $this->prevId;
}
public function getNextId() {
return $this->nextId;
}
}
Check the code generated in the ViewDetal link and modify for the Prev/Net links in the _view file using
$model(or $data)->prevId/nextId
in the array('id'=>#) section.
Taking the original answer and adapting it for Yii2 with a little clean up:
/**
* [nextOrPrev description]
* #source http://stackoverflow.com/questions/8872101/get-next-previous-id-record-in-database-on-yii
* #param integer $currentId [description]
* #param string $nextOrPrev [description]
* #return integer [description]
*/
public static function nextOrPrev($currentId, $nextOrPrev = 'next')
{
$order = ($nextOrPrev == 'next') ? 'id ASC' : 'id DESC';
$records = \namespace\path\Model::find()->orderBy($order)->all();
foreach ($records as $i => $r) {
if ($r->id == $currentId) {
return ($records[$i+1]->id ? $records[$i+1]->id : NULL);
}
}
return false;
}
My implementation is based on SearchModel.
Controller:
public function actionView($id)
{
// ... some code before
// Get prev and next orders
// Setup search model
$searchModel = new OrderSearch();
$orderSearch = \yii\helpers\Json::decode(Yii::$app->getRequest()->getCookies()->getValue('s-' . Yii::$app->user->identity->id));
$params = [];
if (!empty($orderSearch)){
$params['OrderSearch'] = $orderSearch;
}
$dataProvider = $searchModel->search($params);
$sort = $dataProvider->getSort();
$sort->defaultOrder = ['created' => SORT_DESC];
$dataProvider->setSort($sort);
// Get page number by searching current ID key in models
$pageNum = array_search($id, array_column($dataProvider->getModels(), 'id'));
$count = $dataProvider->getCount();
$dataProvider->pagination->pageSize = 1;
$orderPrev = $orderNext = null;
if ($pageNum > 0) {
$dataProvider->pagination->setPage($pageNum - 1);
$dataProvider->refresh();
$orderPrev = $dataProvider->getModels()[0];
}
if ($pageNum < $count) {
$dataProvider->pagination->setPage($pageNum + 1);
$dataProvider->refresh();
$orderNext = $dataProvider->getModels()[0];
}
// ... some code after
}
OrderSearch:
public function search($params)
{
// Set cookie with search params
Yii::$app->response->cookies->add(new \yii\web\Cookie([
'name' => 's-' . Yii::$app->user->identity->id,
'value' => \yii\helpers\Json::encode($params['OrderSearch']),
'expire' => 2147483647,
]));
// ... search model code here ...
}
PS: be sure if you can use array_column for array of objects.
This works good in PHP 7+ but in lower versions you got to extract id by yourself. Maybe it's good idea to use array_walk or array_filter in PHP 5.4+
Full implemenentation with performance improvement by using DB engine/optimization (when id acts as primary key):
Model:
public static function getNextPrevId($currentId)
{
$queryprev = new Query();
$queryprev->select('max(id)')->from(self::tableName())->where('id<:id',['id'=>$currentId]);
$querynext = new Query();
$querynext->select('min(id)')->from(self::tableName())->where('id>:id',['id'=>$currentId]);
return [ $queryprev->scalar(), $querynext->scalar()];
}
Controller:
public function actionView($id) {
return $this->render('view', [
'model' => $this->findModel($id),
'nextprev' => YourModel::getNextPrevId($id),
]);
}
View:
<?= !is_null($nextprev[0]) ? Html::a('⇦', ['view', 'id' => $nextprev[0]], ['class' => 'btn btn-primary']) : '' ?>
<?= !is_null($nextprev[1]) ? Html::a('⇨', ['view', 'id' => $nextprev[1]], ['class' => 'btn btn-primary']) : '' ?>
The previous solutions are problematic when you get the the first or last record and they are making multiple calls to the database. Here is my working solution which operates on one query, handles end-of-table and disables the buttons at end-of-table:
Within the model:
public static function NextOrPrev($currentId)
{
$records = <Table>::find()->orderBy('id DESC')->all();
foreach ($records as $i => $record) {
if ($record->id == $currentId) {
$next = isset($records[$i - 1]->id)?$records[$i - 1]->id:null;
$prev = isset($records[$i + 1]->id)?$records[$i + 1]->id:null;
break;
}
}
return ['next'=>$next, 'prev'=>$prev];
}
Within the controller:
public function actionView($id)
{
$index = <modelName>::nextOrPrev($id);
$nextID = $index['next'];
$disableNext = ($nextID===null)?'disabled':null;
$prevID = $index['prev'];
$disablePrev = ($prevID===null)?'disabled':null;
// usual detail-view model
$model = $this->findModel($id);
return $this->render('view', [
'model' => $model,
'nextID'=>$nextID,
'prevID'=>$prevID,
'disableNext'=>$disableNext,
'disablePrev'=>$disablePrev,
]);
}
Within the view:
<?= Html::a('Next', ['view', 'id' => $nextID], ['class' => 'btn btn-primary r-align btn-sm '.$disableNext]) ?>
<?= Html::a('Prev', ['view', 'id' => $prevID], ['class' => 'btn btn-primary r-align btn-sm '.$disablePrev]) ?>