I am trying to save multiple images on the server. Lets start from the beginning:
//I use this function for testing
function testSave(){
$this->_renderChart(156);
}
//This function takes chart_id as a parameter to render a proper chart.
function _renderChart($chart_id = null){
if(!$chart_id)
return false;
$chartFilterList = $this->getChartFilterListFromId($chart_id);
$this->loadChartFromId($chart_id, $chartFilterList);
$this->layout = 'analytics\chart_one.ctp';
}
The above function's view contains all the necessary scripts to render the chart. This is the part that is translating the rendered chart into base64string and saves it:
//../views/layouts/analytics/chart_one.ctp
<script type="text/javascript">
$(document).ready(function(){
saveChartAsImage('#chart1');
});
</script>
And the above function's body:
function saveChartAsImage(div){
var base64string = $(div).jqplotToImageStr();
$.ajax({
url: 'saveImage',
type: "POST",
dataType: "html",
data:"data=" + base64string
});
}
}
This is not even close to be working. Am I doing something wrong here?
If these functions are controller actions you can use $this->response->body() in controller's afterFilter() callback to get the response content and save it to file. If these are helper functions you can get the content in afterLayout() or afterRender() callbacks of the helper using $this->_View->Blocks->get('content');
I advise creating a behavior, and add the action beforeValidate();
After that make the conditions necessary to invoke the specific actions (listed in your question).
Example:
app/Model/Behavior/ChartBehavior.php
class ChartBehavior extends ModelBehavior {
// if necessary, create a setup action
public function setup(Model $Model, $settings = array()) { }
public function upload(Model $Model) {
// use the $Model->data to see all information from your form
debug($Mode->data);
// now call your functions below to upload
}
public function line_chart($chart_id = null){
//magic...
}
public function bar_chart($chart_id = null){
//magic...
}
public function pie_chart($chart_id = null){
//magic...
}
I hope it helps you.
Related
I try to render an action with a dedicated view in a modal window with an ajax call in Zend Framework 2.
This is my controller action :
public function myAction()
{
$htmlViewPart = new ViewModel();
$htmlViewPart->setTemplate('path/to/my/view')
->setTerminal(true)
->setVariables(['arrayVar' => ['a', 'b', 'c']]);
return $htmlViewPart;
}
The view :
<?php
foreach($arrayVar as $k => $v)
{
echo $k . ':' . $v . '<br>';
}
The js :
$(".my-modal-link").click(function() {
$('#myModal .modal-body').load($(this).data('/url/to/my/action'));
});
This not do the trick. I also tried with a JSON model too:
public function myAction()
{
$htmlViewPart = new ViewModel();
$htmlViewPart->setTemplate('path/to/my/view')
->setTerminal(true)
->setVariables(['arrayVar' => ['a', 'b', 'c']]);
$htmlOutput = $this->getServiceLocator()->get('viewrenderer')->render($htmlViewPart);
$jsonModel = new JsonModel();
$jsonModel->setVariables(['html' => $htmlOutput]);
return $jsonModel;
}
But the final render in the modal is something like :
{"html":"0:a\u003Cbr\u003E1:b\u003Cbr\u003E2:c\u003Cbr\u003E"}
Have an idea to how achieve that?
All you need is disabling the layout using setTerminal() and returning proper model from your controller to render HTML output in your modal.
In your case, you have to return a ViewModel instance. So, your first approach is correct. This should work:
$htmlViewPart = new ViewModel();
$htmlViewPart->setTemplate('path/to/my/view')
->setTerminal(true)
->setVariables(['arrayVar' => ['a', 'b', 'c']]);
return $htmlViewPart;
The second case is; you're trying to use a HTML output as json data. Try to change your ajax loading mechanism similar to this:
$(".my-modal-link").click(function() {
$.get("/url/to/my/action", function(data) {
$('#myModal .modal-body').html(data);
});
});
This will be append the rendered output (which doesnt have a layout) into modal's body. You may also want to read this for JsonModel scenario.
Hope it helps.
I found a solution.
Just create an empty layout returning content.
// Application/view/layout/ajax.phtml
<?php
echo $this->content;
And set this template in the action view
<?php
$this->layout()->setTemplate('layout/ajax');
It works now with Jquery $.load() / ViewModel strategy
Have the same problem this works...
$.get("<?php echo $this->url('your url'); ?>", function(data)
{
console.log(data);
$('#myModal .modal-body').html(data);
});
I have this application where I use Codeigniter as backend and Backbone as frontend. Now I use the RESTful API from https://github.com/philsturgeon/codeigniter-restserver. I want to fetch RSS feeds, so I created a RSS-model.php in application->models:
<?php
class Rss_model extends CI_Model
{
var $table_name = 'artist_news';
var $primary_key = 'news_id';
function get_all_rss_feeds()
{
$this->db->select($this->primary_key);
$this->db->from($this->table_name);
return $this->db->get();
}
}
?>
and then in application->controllers I created the folder api in which I created the file rss.php:
<?php
require(APPPATH.'libraries/REST_Controller.php');
class rss extends REST_Controller{
public function get_all_rss_feeds_get()
{
$this->load->database();
$this->load->model('rss_model');
$data = $this->rss_model->get_all_rss_feeds();
if($data) {
$this->response($data, 200);
} else {
$this->response(array('error' => 'Couldn\'t find any news!'), 404);
}
}
}
?>
So far so good, it returns an array of text with a lot of rss-feeds, but NOT in JSON format, which I need for my frontend.
Does anyone know what the issue is here?
Thanks in advance...
[EDIT]
My Backbone Code looks like this:
function (App, Backbone) {
var Rss = App.module();
Rss.View = Backbone.View.extend({
template: 'rss',
initialize: function() {
this.listenTo(this.collection, 'all', this.render)
},
serialize: function() {
return this.collection ? this.collection.toJSON() : [];
}
});
Rss.RssCollection = Backbone.Collection.extend({
url: function() {
return '/myproject/index.php/api/rss/get_all_rss_feeds/';
}
});
return Rss;
}
go to config/rest.php file and find this line :
$config['rest_default_format'] = 'xml';
change it to :
$config['rest_default_format'] = 'json';
I think you missed the result in return in the model please check below
function get_all_rss_feeds()
{
$this->db->select($this->primary_key);
$this->db->from($this->table_name);
return $this->db->get()->result();
}
If you are usign the Phil Sturgeon REST library you need to append the format type in the URL. Example:
http://example.com/books.json
http://example.com/books?format=json
If you want it in another format, let's say XML, you just need to pass the new format in the URI, doesn't need to change anything in your code. Example:
http://example.com/books.xml
http://example.com/books?format=xml
Further reading:
Content-Type Section - https://github.com/philsturgeon/codeigniter-restserver
I want to perform CRUD operations through REST, I am implementing this in codeigniter, The code whatever I pasted here is working, but I have to handle a way to fetch all the datas from the database and also a way to fetch the data by id. Is there any best way to do this?
Backbone.js
(function(){
Backbone.emulateHTTP = true;
//Backbone.emulateJSON = true;
window.App = {
Models: {},
Collections: {},
Views: {},
Router: {}
};
App.Models.Task = Backbone.Model.extend({
defaults: {
title: '',
done: 0
},
urlRoot: 'index.php/taskController/task'
});
})();
Controller
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
require(APPPATH.'libraries/REST_Controller.php');
class taskController extends REST_Controller {
public function task_get($id){
$this->load->model('Task', 'task');
$data['task'] = $this->task->findbyid($id);
}
public function tasks_get(){
$this->load->model('Task','task');
$data['task'] = $this->task->find();
$this->response($data,200);
}
public function task_put($id)
{
# code...
$this->load->model('Task', 'task');
$data = json_decode(file_get_contents('php://input'), true);
// $data['title'] = $var['title'];
// $data['done'] = $var['done'];
echo var_dump($data);
$data['task'] = $this->task->updatebyid($id,$data);
//$this->response($data,200);
}
public function task_delete($id){
$this->load->model('Task','task');
$data['task'] = $this->task->delete($id);
}
public function task_post(){
$this->load->model('Task','task');
$data = json_decode(file_get_contents('php://input'),true);
return $data['task'] = $this->task->create($data);
}
}
I use /get/id for the items and /list/number_to_show/limit
So add a list_get($number, $limit)
method
if code for a /get/id is no id is passed, Send the entire lot ?
The principle of REST is that the CRUD actions are represented by the HTTP verbs. GET = select, PUT = update, POST = create and DELETE = delete.
You use nouns in your URL to represent your resources (e.g. tasks).
From your CI code it looks like you use always GET and have verbs+nouns in your URLs.
In REST, to get all tasks you would need to do GET http://example.com/tasks. To get one specific task you would need to do GET http://example.com/tasks/1234
Please read http://info.apigee.com/Portals/62317/docs/web%20api.pdf to understand the principle.
I have come up with the following bits of code to call a method via AJAX in my PHP classes:
PHP:
class Ajax extends Controller {
private $class;
private $method;
private $params;
function __construct()
{
$this->params = $_POST; // Call params
$call = explode('->', $this->params['call']);
$this->class = new $call[0]; // e.g. controller->method
$this->method = $call[1];
array_shift($this->params);
$this->parse();
}
public function index()
{
//Dummy
}
public function parse()
{
$r = '';
$r = call_user_func_array(array($this->class, $this->method), $this->params);
echo $r;
}
}
Client:
function creditCheck2(id)
{
$.post(ROOT + 'Ajax', {call: 'Record->creditState', id: id, enquiryid: enquiryId}, function(data) {
alert(data)
}, 'json')
}
It seems to work great, but is it secure and could it be better?
Just for reference, I have added my code with the changes suggested by the answers:
class Call extends Controller {
private $class;
private $method;
private $params;
private $authClasses = array(
'Gallery'
);
function __construct()
{
$this->params = $_POST; // Call params
$call = explode('->', $this->params['call']);
if(!in_array($call[0], $this->authClasses))
{
die();
}
$this->class = new $call[0]; // e.g. controller->method
$this->method = $call[1];
unset($this->params['call']);
$this->parse();
}
public function parse()
{
$r = '';
$param = array();
// Params in any order...
$mRef = new ReflectionMethod($this->class, $this->method);
foreach($mRef->getParameters() as $p) {
$param[$p->name] = $this->params[$p->name];
}
$this->params = $param;
if($r = #call_user_func_array(array($this->class, $this->method), $this->params))
{
echo $r;
}
else {
}
}
}
Small issues
It could be better in that array_shift($this->params) unnecessarily assumes that the first item in the params array will always be call. That's not true and it does not agree with the direct access $this->params['call'] you are doing a little earlier. The array_shift should be replaced with simply unset($this->params['call']).
Bigger issues
There is also the problem that the order of values in the params array must match the order of parameters in the signature of the method you are trying to call. I don't think there is a guarantee that the order will be the same as the order of the parameters in the AJAX request, so that's a theoretical problem.
VERY big problem
More importantly, this way of doing things forces the author of the AJAX code to match the order of parameters in the signature of the method you are trying to call. This introduces a horrible level of coupling and is a major problem. What's worse, changing the order of the parameters by mistake will not be apparent. Consider:
public function bankTransfer($fromAccount, $toAccount, $amount);
$.post(ROOT + 'Ajax', {
call: 'Bank->bankTransfer',
from: "sender",
to: "recipient",
amount: 42
}, function(data) { ... });
This would work. But if you do this
$.post(ROOT + 'Ajax', {
call: 'Bank->bankTransfer',
to: "recipient", // swapped the order of
from: "sender", // these two lines
amount: 42
}, function(data) { ... });
You will get the opposite result of what is expected. I believe it's immediately obvious that this is extremely bad.
To solve the problem you would have to use reflection to match the array keys in $this->params with the formal names of the parameters of the method being called.
Security
Finally, this code is insecure in that anyone can make a request that directs your code to call any method of any class with the appropriate parameters -- even methods that should not be accessible from a web environment.
This is another serious problem and cannot really be fixed unless you introduce some type of filtering to the dispatch logic.
It seems to work great, but is it secure and could it be better?
Are you using your own framework or using other framework? I believe that it isn't secure at all, if the attacker know what might be inside your framework. For example: there is database class in your framework, attacker can do the following:
{call: 'Database->execute', sql: 'SELECT * FROM information_schema.`tables`'}
Filtering
You can limit the number of class that you allow user to access. For example:
if (!in_array($this->class, array('Record', 'Hello'))) {
die();
}
Reflection
This is sample of reflection that I just learn (Thanks to #Jon for the reference). This solve the problem of passing argument in different order from the PHP function.
class Email
{
public function send($from, $to, $msg) {
return "Send $from to $to: $msg";
}
}
$rawParam = array('msg' => 'Hello World',
'to' => 'to#gmail.com',
'from' => 'from#gmail.com');
$param = array();
// Rearrange
$methodRef = new ReflectionMethod('Email', 'send');
foreach($methodRef->getParameters() as $p) {
$param[$p->name] = $rawParam[$p->name];
}
var_dump($rawParam);
var_dump($param);
I have a website where I am wanting to get some query results through AJAX and JSON, but I have absolutely no idea how to do it, I have this function,
public function category() {
$table = $this->uri->segment(2);
$content_id = $this->uri->segment(3);
$data['content'] = $this->site_model->get_content($table, $content_id);
$this->load->view('template/right-content', $data);
}
Essentially the query that is run is dynamic depending on what url is being passed, what I need to is, for the user clicks a link something like
Read the blog
From this link I get blog and 1 passed to the query, but I need to load the results in a view that is loaded in to my main template and then everytime a link is clicked do the same thing without overwriting the previous data, does anyone have any idea how to do this?
If I understand you correctly, you need to send an Ajax request to that url and then append it to the appropriate place in your document. Something like this:
$("#blog").click(function () {
var url = $(this).attr("href");
$.ajax ({
url: url,
type: "POST",
success : function (html) {
$("#someDiv").append(html);
}
});
});
So that Codeigniter view should only contain the content, really, and perhaps some markup necessary to style it. The containers where the content goes should already be in the page where the link is originating.
Or, if you want actually want your data to come back as JSON you could do something like this
public function category() {
$table = $this->uri->segment(2);
$content_id = $this->uri->segment(3);
echo json_encode($this->site_model->get_content($table, $content_id));
}
AND, if you use the above authors method of using $.append, you'd want to modify your controller as such:
public function category() {
$table = $this->uri->segment(2);
$content_id = $this->uri->segment(3);
$data['content'] = $this->site_model->get_content($table, $content_id);
echo $this->load->view('template/right-content', $data, TRUE);
}