Why I cannot post image through twitter api? - api

this is my code, i am trying to post tweet with image, but only text get posted?I really really want to post image as well. I am pulling my hair out for that, HELP!!?
<?php
error_reporting(E_ALL);
require_once('TwitterAPIExchange.php');
//echo 'start';
/** Set access tokens here - see: https://dev.twitter.com/apps/ **/
require_once('connect.php');
$recid=$_GET['recid'];
//echo $recid;
$dsn='mysql:host='.$hostname.';dbname=twitter_db';
try{
$dbh=new PDO($dsn,$username,$password);
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$stmt=$dbh->prepare("SELECT * FROM gr_twitter WHERE recid=:recid");
$stmt->execute(array(
'recid'=>$recid
));
$foundResult=$stmt->fetchAll();
$tweetmsg=$foundResult[0]['tweet'];
$tweetImage=$foundResult[0]['tweetImageName'];
$timestamp=$foundResult[0]['sentTimestamp'];
print_r($foundResult);
$stmt2=$dbh->prepare("UPDATE gr_twitter SET sent=1 WHERE recid=:recid");
$stmt2->execute(array(
'recid'=>$recid
));
}
catch(PDOException $e){}
// Perform a GET request and echo the response **/
/** Note: Set the GET field BEFORE calling buildOauth(); **/
$url = 'https://api.twitter.com/1.1/statuses/update.json';
$requestMethod='POST';
////images is stored in D:\Databases\RC_Data_FMS\images\Files\images\tweetImage folder
$tweetImage='D:\Databases\RC_Data_FMS\images\Files\images\tweetImage/images.jpg';
$postfields = array(
'status' => $tweetmsg,
'media' => "#{$tweetImage}"
);
/** POST fields required by the URL above. See relevant docs as above **/
//print_r($postfields).'<br />';
$twitter = new TwitterAPIExchange($Yh_settings);
$response= $twitter->buildOauth($url, $requestMethod)
->setPostfields($postfields)
->performRequest();
echo "Success, you just tweeted!<br />";
var_dump(json_decode($response));
//////////////////////////////////////////////////////////////////////////
function objectToArray($d)
{
if (is_object($d)) {
// Gets the properties of the given object
// with get_object_vars function
$d = get_object_vars($d);
}
if (is_array($d)) {
/*
* Return array converted to object
* Using __FUNCTION__ (Magic constant)
* for recursive call
*/
// return array_map(__FUNCTION__, $d);
} else {
// Return array
// return $d;
}
}
?>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

I recommend you to use tmhOAuth library if you want to post images that are located in your server.
Here you have an example:
<?php
require_once('./tmhOAuth.php');
$tmhOAuth = new tmhOAuth(array(
'consumer_key' => CONSUMER_KEY,
'consumer_secret' => CONSUMER_SECRET,
'user_token' => OAUTH_TOKEN,
'user_secret' => OAUTH_TOKEN_SECRET
));
$tweetText = 'Your text here';
$imageName = 'picture.png';
$imagePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . $imageName;
$code = $tmhOAuth->request(
'POST',
$tmhOAuth->url('1.1/statuses/update_with_media'),
array(
'media[]' => "#{$imagePath};type=image/png;filename={$imageName}",
'status' => $tweetText
),
true, // use auth
true // multipart
);
?>
Hope this helps!

Related

How do I send multiple query parameters to the api?

I'm calling the API to get a list of shipments but I can't seem to page through the results.
The API call is successful with only one query parameter but when I call it with two query parameters, I get the error "The signature is invalid. Verify and try again". I'm including my test code below.
<?php
function sign($method, $url, $data, $consumerSecret, $tokenSecret)
{
$url = urlEncodeAsZend($url);
$data = urlEncodeAsZend(http_build_query($data, '', '&'));
$data = implode('&', [$method, $url, $data]);
$secret = implode('&', [$consumerSecret, $tokenSecret]);
return base64_encode(hash_hmac('sha1', $data, $secret, true));
}
function urlEncodeAsZend($value)
{
$encoded = rawurlencode($value);
$encoded = str_replace('%7E', '~', $encoded);
return $encoded;
}
// REPLACE WITH YOUR ACTUAL DATA OBTAINED WHILE CREATING NEW INTEGRATION
$consumerKey = 'htj8ze6ntr0mz1s4hjxrqeicia8rxgt4';
$consumerSecret = 'djjzdwfgbbr7ganlkv01qr6p3l7ptvfe';
$accessToken = '60o0mfrvqnjvin7tjuqsv37arijrqe9e';
$accessTokenSecret = 'caq9wfdx99zaygwgbhw91i9imj89p4zb';
$method = 'GET';
/* test 1 PASS */
//$url = 'http://localhost/rest/V1/shipments/';
//$qs = ['searchCriteria'=>'all'];
/* test 2 PASS */
//$url = 'http://localhost/rest/V1/shipments/';
//$qs = ['searchCriteria[pageSize]'=>'10'];
/* test 3 FAIL "The signature is invalid. Verify and try again" */
$url = 'http://localhost/rest/V1/shipments/';
$qs = ['searchCriteria[pageSize]'=>'10', 'searchCriteria[currentPage]'=>'1'];
$data = [
'oauth_consumer_key' => $consumerKey,
'oauth_nonce' => md5(uniqid(rand(), true)),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_token' => $accessToken,
'oauth_version' => '1.0',
];
$data = array_merge($data, $qs);
$data['oauth_signature'] = sign($method, $url, $data, $consumerSecret, $accessTokenSecret);
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $url .'?' .http_build_query($qs),
CURLOPT_HTTPHEADER => [
'Authorization: OAuth ' . http_build_query($data, '', ',')
]
]);
$result = curl_exec($curl);
curl_close($curl);
echo($result);
The code includes three tests.
If I uncomment test 1 and comment test 2 and 3, the code works properly and I get a list of shipments.
If I uncomment test 2 and comment test 1 and 3, the code works properly and I get a list of shipments.
If I run the code as is, I get the the message "The signature is invalid. Verify and try again."
I'm running Magento ver. 2.3.2
The trick is to sort the parameters. I have some client code anyone is interested.
<?php
function sign($method, $url, $data, $consumerSecret, $tokenSecret)
{
$url = urlEncodeAsZend($url);
$data = urlEncodeAsZend(http_build_query($data, '', '&'));
$data = implode('&', [$method, $url, $data]);
$secret = implode('&', [$consumerSecret, $tokenSecret]);
return base64_encode(hash_hmac('sha1', $data, $secret, true));
}
function urlEncodeAsZend($value)
{
$encoded = rawurlencode($value);
$encoded = str_replace('%7E', '~', $encoded);
return $encoded;
}
function recursive_sort(&$array) {
foreach ($array as &$value) {
if (is_array($value)) recursive_sort($value);
}
return ksort($array);
}
// REPLACE WITH YOUR ACTUAL DATA OBTAINED WHILE CREATING NEW INTEGRATION
$consumerKey = 'htj8ze6ntr0mz1s4hjxrqeicia8rxgt4';
$consumerSecret = 'djjzdwfgbbr7ganlkv01qr6p3l7ptvfe';
$accessToken = '60o0mfrvqnjvin7tjuqsv37arijrqe9e';
$accessTokenSecret = 'caq9wfdx99zaygwgbhw91i9imj89p4zb';
$method = 'GET';
/* test 1 PASS */
//$url = 'http://localhost/rest/V1/shipments/';
//$qs = ['searchCriteria'=>'all'];
/* test 2 PASS */
//$url = 'http://localhost/rest/V1/shipments/';
//$qs = ['searchCriteria[pageSize]'=>'10'];
/* test 3 FAIL "The signature is invalid. Verify and try again" */
$url = 'http://localhost/rest/V1/shipments/';
$qs = ['searchCriteria'=>['pageSize'=>10,'currentPage'=>1]];
$data = [
'oauth_consumer_key' => $consumerKey,
'oauth_nonce' => md5(uniqid(rand(), true)),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_token' => $accessToken,
'oauth_version' => '1.0',
];
$data = array_merge($data, $qs);
recursive_sort($data);
$data['oauth_signature'] = sign($method, $url, $data, $consumerSecret, $accessTokenSecret);
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $url .'?' .http_build_query($qs),
CURLOPT_HTTPHEADER => [
'Authorization: OAuth ' . http_build_query($data, '', ',')
]
]);
$result = curl_exec($curl);
curl_close($curl);
echo($result);
Though this question is old, I want to post the answer for future cases.
The code in the question is good, and it helped me a lot.
It is needed to sort parameters by key. Also, please consider that the searchCriteria is a multidimensional array. So, the array must be sorted by key recursively.

How the query used in Yii2

Can you help me. i want to like example but on my source code it becomes empty emty. What is the query or source code in my project? thank You.
in Controller
public function actionView($id)
{
$con = Yii::$app->db;
$sql = $con->createCommand("SELECT * FROM track where collecting_id=$id ORDER BY collecting_id desc");
$posts = $sql->query();
return $this->render('view', [
'model' => $this->findModel($id),
'posts' => $posts,
]);
}
in View
<div class="timeline__items">
<?php
foreach($posts as $row)
{
?>
<div class="timeline__item">
<div class="timeline__content">
<h2><?php echo $row['status']; ?></h2>
<p><?php echo $row['tanggal']; ?></p>
</div>
</div>
<?php
}
?>
</div>
if the $id on the query is replaced with 'PMUEI' the result is result
Use ActiveDataProvider
public function actionView($id)
{
$model = $this->findModel($id);
$hotel = Track::find()->where(['collecting_id' => $model->collecting_id]);
$posts = new ActiveDataProvider([
'query' => $hotel,
]);
// $con = Yii::$app->db;
// $sql = $con->createCommand(
// "SELECT * FROM track where collecting_id=:collecting_id ORDER BY collecting_id desc",
// [':collecting_id' => '$id']
// );
// $posts = $sql->queryAll();
return $this->render(
'view', [
'model' => $this->findModel($id),
'posts' => $posts,
]);
}
the result is error .
Its always good to bind parameters when comparing columns with any such input that is provided by the user or can be edited by the user as in your case is the $id that you are passing as a parameter to the actionView(). And then you need to use queryAll() or queryOne() in case you want multiple or single rows returned.
So you should change your query to the following
public function actionView($id)
{
$con = Yii::$app->db;
$sql = $con->createCommand(
"SELECT * FROM track where collecting_id=:collecting_id ORDER BY collecting_id desc",
[':collecting_id' => $id]
);
$posts = $sql->queryAll();
return $this->render(
'view', [
'model' => $this->findModel($id),
'posts' => $posts,
]
);
}
Apart from the above, you should use ActiveRecord. Active Record provides an object-oriented interface for accessing and manipulating data stored in databases. Read Here to make your life easier.

Creating an issue in JIRA using REST API - PHP YII2

I'm trying to create an issue in JIRA from my PHP YII2 framework.
What I'm trying to do is - Whenever I create a new version in my system I want that an issue JIRA will be created automatically for this version.
I've found examples in CURL but so far it's not working.
I don't even get any error message. It creates a new version in my system, but nothing happens in JIRA, looks like it's not even trying to connect to JIRA.
This is my VersionController.php -
<?php
namespace app\controllers;
require_once("Curl.php");
use Yii;
use app\models\Version;
use app\models\VersionSearch;
use app\models\Binfile;
use app\models\VersionStatus;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\swiftmailer\Mailer;
use yii\web\UnauthorizedHttpException;
use linslin\yii2\curl;
use understeam\yii2\httpclient;
use understeam\yii2\jira;
/**
* VersionController implements the CRUD actions for Version model.
*/
class VersionController extends Controller
{
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
],
],
'access' => [
'class' => \yii\filters\AccessControl::className(),
'only' => ['index','create','update','view'],
'rules' => [
// allow authenticated users
[
'allow' => true,
'roles' => ['#'],
],
// everything else is denied
],
],
];
}
/**
* Lists all Version models.
* #return mixed
*/
public function actionIndex()
{
if (\Yii::$app->user->can('deleteVersion')) {
$template = '{view} {update} {delete} ';
}
else if((\Yii::$app->user->can('changeStatus')) || (\Yii::$app->user->can('uploadVersion'))){
$template = '{view} {update}';
}
else{$template = '{view}';
}
$searchModel = new VersionSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'template' => $template,
]);
}
/**
* Displays a single Version model.
* #param integer $id
* #return mixed
*/
public function actionView($id)
{
return $this->render('view', [
'model' => $this->findModel($id),
]);
}
/**
* Creates a new Version model.
* If creation is successful, the browser will be redirected to the 'view' page.
* #return mixed
*/
public function actionCreate()
{
if(!\Yii::$app->user->can('createVersion')){
throw new UnauthorizedHttpException("Access denied: You don't have permission to create a version");
}else{
$model = new Version();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
//$this->actionSend();
$this->actionPostExample();
// $this->actionGetExample();
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
}
/**
* Updates an existing Version model.
* If update is successful, the browser will be redirected to the 'view' page.
* #param integer $id
* #return mixed
*/
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
/**
* Deletes an existing Version model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* #param integer $id
* #return mixed
*/
public function actionDelete($id)
{
if(!\Yii::$app->user->can('isAdmin')){
throw new UnauthorizedHttpException("Access denied: Only Admin can perform this action!!!");
}else{
$this->findModel($id)->delete();
return $this->redirect(['index']);
}
}
/**
* Finds the Version model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* #param integer $id
* #return Version the loaded model
* #throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id)
{
if (($model = Version::findOne($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
public function actionSend()
{
Yii::$app->mailer->compose()
->setFrom('jenya#ttttt.com')
->setTo('jenya#tttt.com')
->setSubject('Message test')
->setTextBody('Plain text content')
->setHtmlBody('<b>test</b>')
->send();
}
public function actionPostExample()
{
define('JIRA_URL', 'http://jiratest.../');
define('USERNAME', 'jenya');
define('PASSWORD', 'password');
function post_to($resource, $data)
{
$jdata = json_encode($data);
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_POST => 1,
CURLOPT_URL => JIRA_URL . '/rest/api/latest/' . $resource,
CURLOPT_USERPWD => USERNAME . ':' . PASSWORD,
CURLOPT_POSTFIELDS => $jdata,
CURLOPT_HTTPHEADER => array('Content-type: application/json'),
CURLOPT_RETURNTRANSFER => true
));
$result = curl_exec($ch);
curl_close($ch);
return json_decode($result);
}
$new_issue = array(
'fields' => array(
'project' => array('key' => 'key'),
'issuetype' => array('name' => 'Version Integration Task'),
'summary' => 'Test via REST',
'components' => 'General',
'customfield_10110' => 'name of value',
'fixVersions' => 'name of version',
'Description' => 'Description of issue goes here.',
//'labels' => array('a','b')
)
);
function create_issue($issue)
{
return post_to('issue', $issue);
}
$result = create_issue($new_issue);
if (property_exists($this, 'errors'))
{
echo "Error(s) creating issue:\n";
var_dump($result);
}
else
{
echo "New issue created at " . JIRA_URL ."/browse/{$result}\n";
}
}
}
Curl.php-
<?php
/**
* Yii2 cURL wrapper
* With RESTful support.
*
* #category Web-yii2
* #package yii2-curl
* #author Nils Gajsek <info#linslin.org>
* #copyright 2013-2015 Nils Gajsek<info#linslin.org>
* #license http://opensource.org/licenses/MIT MIT Public
* #version 1.0.7
* #link http://www.linslin.org
*
*/
namespace linslin\yii2\curl;
use Yii;
use yii\base\Exception;
use yii\helpers\Json;
use yii\web\HttpException;
/**
* cURL class
*/
class Curl
{
// ################################################ class vars // ################################################
/**
* #var string
* Holds response data right after sending a request.
*/
public $response = null;
/**
* #var integer HTTP-Status Code
* This value will hold HTTP-Status Code. False if request was not successful.
*/
public $responseCode = null;
/**
* #var array HTTP-Status Code
* Custom options holder
*/
private $_options = array();
/**
* #var object
* Holds cURL-Handler
*/
private $_curl = null;
/**
* #var array default curl options
* Default curl options
*/
private $_defaultOptions = array(
CURLOPT_USERAGENT => 'Yii2-Curl-Agent',
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 30,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
);
// ############################################### class methods // ##############################################
/**
* Start performing GET-HTTP-Request
*
* #param string $url
* #param boolean $raw if response body contains JSON and should be decoded
*
* #return mixed response
*/
public function get($url, $raw = true)
{
return $this->_httpRequest('GET', $url, $raw);
}
/**
* Start performing HEAD-HTTP-Request
*
* #param string $url
*
* #return mixed response
*/
public function head($url)
{
return $this->_httpRequest('HEAD', $url);
}
/**
* Start performing POST-HTTP-Request
*
* #param string $url
* #param boolean $raw if response body contains JSON and should be decoded
*
* #return mixed response
*/
public function post($url, $raw = true)
{
return $this->_httpRequest('POST', $url, $raw);
}
/**
* Start performing PUT-HTTP-Request
*
* #param string $url
* #param boolean $raw if response body contains JSON and should be decoded
*
* #return mixed response
*/
public function put($url, $raw = true)
{
return $this->_httpRequest('PUT', $url, $raw);
}
/**
* Start performing DELETE-HTTP-Request
*
* #param string $url
* #param boolean $raw if response body contains JSON and should be decoded
*
* #return mixed response
*/
public function delete($url, $raw = true)
{
return $this->_httpRequest('DELETE', $url, $raw);
}
/**
* Set curl option
*
* #param string $key
* #param mixed $value
*
* #return $this
*/
public function setOption($key, $value)
{
//set value
if (in_array($key, $this->_defaultOptions) && $key !== CURLOPT_WRITEFUNCTION) {
$this->_defaultOptions[$key] = $value;
} else {
$this->_options[$key] = $value;
}
//return self
return $this;
}
/**
* Unset a single curl option
*
* #param string $key
*
* #return $this
*/
public function unsetOption($key)
{
//reset a single option if its set already
if (isset($this->_options[$key])) {
unset($this->_options[$key]);
}
return $this;
}
/**
* Unset all curl option, excluding default options.
*
* #return $this
*/
public function unsetOptions()
{
//reset all options
if (isset($this->_options)) {
$this->_options = array();
}
return $this;
}
/**
* Total reset of options, responses, etc.
*
* #return $this
*/
public function reset()
{
if ($this->_curl !== null) {
curl_close($this->_curl); //stop curl
}
//reset all options
if (isset($this->_options)) {
$this->_options = array();
}
//reset response & status code
$this->_curl = null;
$this->response = null;
$this->responseCode = null;
return $this;
}
/**
* Return a single option
*
* #param string|integer $key
* #return mixed|boolean
*/
public function getOption($key)
{
//get merged options depends on default and user options
$mergesOptions = $this->getOptions();
//return value or false if key is not set.
return isset($mergesOptions[$key]) ? $mergesOptions[$key] : false;
}
/**
* Return merged curl options and keep keys!
*
* #return array
*/
public function getOptions()
{
return $this->_options + $this->_defaultOptions;
}
/**
* Get curl info according to http://php.net/manual/de/function.curl-getinfo.php
*
* #return mixed
*/
public function getInfo($opt = null)
{
if ($this->_curl !== null && $opt === null) {
return curl_getinfo($this->_curl);
} elseif ($this->_curl !== null && $opt !== null) {
return curl_getinfo($this->_curl, $opt);
} else {
return [];
}
}
/**
* Performs HTTP request
*
* #param string $method
* #param string $url
* #param boolean $raw if response body contains JSON and should be decoded -> helper.
*
* #throws Exception if request failed
*
* #return mixed
*/
private function _httpRequest($method, $url, $raw = false)
{
//set request type and writer function
$this->setOption(CURLOPT_CUSTOMREQUEST, strtoupper($method));
//check if method is head and set no body
if ($method === 'HEAD') {
$this->setOption(CURLOPT_NOBODY, true);
$this->unsetOption(CURLOPT_WRITEFUNCTION);
}
//setup error reporting and profiling
Yii::trace('Start sending cURL-Request: '.$url.'\n', __METHOD__);
Yii::beginProfile($method.' '.$url.'#'.md5(serialize($this->getOption(CURLOPT_POSTFIELDS))), __METHOD__);
/**
* proceed curl
*/
$this->_curl = curl_init($url);
curl_setopt_array($this->_curl, $this->getOptions());
$body = curl_exec($this->_curl);
//check if curl was successful
if ($body === false) {
switch (curl_errno($this->_curl)) {
case 7:
$this->responseCode = 'timeout';
return false;
break;
default:
throw new Exception('curl request failed: ' . curl_error($this->_curl) , curl_errno($this->_curl));
break;
}
}
//retrieve response code
$this->responseCode = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE);
$this->response = $body;
//end yii debug profile
Yii::endProfile($method.' '.$url .'#'.md5(serialize($this->getOption(CURLOPT_POSTFIELDS))), __METHOD__);
//check responseCode and return data/status
if ($this->getOption(CURLOPT_CUSTOMREQUEST) === 'HEAD') {
return true;
} else {
$this->response = $raw ? $this->response : Json::decode($this->response);
return $this->response;
}
}
}
I would really appreciate your help, I don't know what else to try.
Thanks in advance.
There is a bug in VersionController.php / actionPostExample() / post_to. As written I would expect the HTTP post to JIRA to result in an HTTP 404 response.
This line:
CURLOPT_URL => JIRA_URL . '/rest/api/latest/' . $resource,
Should be:
CURLOPT_URL => JIRA_URL . '/rest/api/2/' . $resource,
../latest/... is used in the JIRA api docs pages but it is not part of the rest API. .../rest/api/2/... is compatible with JIRA 6 and 7.
I did it.
This is the function that works for me:
function post_to($resource, $data)
{
$jdata = json_encode($data);
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_POST => true,
CURLOPT_URL => JIRA_URL . '/rest/api/latest/' . $resource,
CURLOPT_USERPWD => USERNAME . ':' . PASSWORD,
CURLOPT_POSTFIELDS => $jdata,
CURLOPT_HTTPHEADER => array('Content-type: application/json'),
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
//CURLOPT_RETURNTRANSFER => true
));
After that I had to fix several things in JSON which are specific for my project.
For easier debugging you can add this:
error_reporting(E_ALL);
ini_set('display_errors', 1);
To get clear errors.

How to upload multiple file at a time using TbActiveForm?

I am using TbActiveForm. I want upload multiple file at a time, Please help me.Thanks
In your TbActiveForm you have to use a widget for multiple file upload. You could write it yourself or use widget like CMultiFileUpload.
Here is reference for CMultiFileUpload.
Example for view:
<?php
$this->widget('CMultiFileUpload', array(
'model'=>$model,
'attribute'=>'photos',
'accept'=>'jpg|gif|png',
'options'=>array(),
'denied'=>'File is not allowed',
'max'=>10, // max 10 files
));
?>
Example for controller:
public function actionCreate()
{
$model = new Photo;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
$type = isset($_GET['type']) ? $_GET['type'] : 'post';
if (isset($_POST['Photo'])) {
$model->attributes = $_POST['Photo'];
$photos = CUploadedFile::getInstancesByName('photos');
// proceed if the images have been set
if (isset($photos) && count($photos) > 0) {
// go through each uploaded image
foreach ($photos as $image => $pic) {
echo $pic->name.'<br />';
if ($pic->saveAs(Yii::getPathOfAlias('webroot').'/photos/path/'.$pic->name)) {
// add it to the main model now
$img_add = new Photo();
$img_add->filename = $pic->name; //it might be $img_add->name for you, filename is just what I chose to call it in my model
$img_add->topic_id = $model->id; // this links your picture model to the main model (like your user, or profile model)
$img_add->save(); // DONE
}
else{
echo 'Cannot upload!'
}
}
}
if ($model->save())
$this->redirect(array('update', 'id' => $model->id));
}
$this->render('create', array(
'model' => $model,
));
}
Source reference.

ZF2 testing - mock object ignored by serviceManager

I'm trying to run tests on my controller in Zend Framework 2.3.
My tested action looks like this:
public function listAction() {
// optional filtering
$filter = $this->params('filter'); // filter type
// params from JSON
$jsonPost = $this->getRequest()->getContent();
$params = json_decode($jsonPost);
$param1 = isset($params->query1) ? $params->query1 : NULL;
$param2 = isset($params->query2) ? $params->query2 : NULL;
$json = Array( // json container
'status' => TRUE,
'data' => Array(),
);
try {
// get data from Model
$list = new Mapping\Books\Listing();
if( !empty($filter)) { // optional filtering
$list->addFilter($filter, $param1, $param2);
}
$data = $list->setOrder()->getList();
// final data mapping to JSON and formating
foreach($data as $isbn => $book) {
$json['data'][$isbn] = Array(
'ISBN' => $book->getISBN(),
'title' => $book->getTitle(),
'rating' => $book->getRating(),
'release_date' => $book->getReleaseDate()->format('F Y'),
'authors' => Array() // multiple
);
// final authors mapping
foreach($book->getAuthors() as $author) {
$json['data'][$isbn]['authors'][] = Array(
'author_id' => $author->getId(),
'author_name' => $author->getName()
);
}
}
} catch(Exception $e) {
$json = Array(
'status' => FALSE,
'error' => $e->getMessage()
);
}
return new JsonModel( $json );
}
My testing method looks like this:
public function testListActionWithoutParams()
{
// object mocking
$listingMock = $this->getMockBuilder('Books\Model\Mapping\Books\Listing')
->disableOriginalConstructor()
->setMethods(Array('getData', 'setOrder'))
->getMock();
$listingMock->expects($this->once())->method('setOrder')
->will($this->returnSelf());
$listingMock->expects($this->once())->method('getData')
->willReturn( Array() ); // for testing is enough
$serviceManager = $this->getApplicationServiceLocator();
$serviceManager->setAllowOverride(true);
$serviceManager->setService('Books\Model\Mapping\Books\Listing', $listingMock);
// dispatch
$this->dispatch('/books');
// routing tests
$this->assertResponseStatusCode(200);
$this->assertModuleName('Books');
$this->assertControllerName('Books\Controller\Index');
$this->assertControllerClass('IndexController');
$this->assertActionName('list');
$this->assertMatchedRouteName('list');
// header tests
$this->assertResponseHeaderContains('Content-type', 'application/json; charset=utf-8');
}
I think I'm missunderstanding something here. My understanding is, that serviceManager will also "notify" autoloader, that actually called class should be replaced by mock object, but it does not.
How can I replace my object with mocked, please ?
Firstly you controller have a lot of logic, what is incorrect.
Secondly, I can give you only workflow of the code:
In your controller you need a method with will be returning list object, so in line:
// get data from Model
$list = new Mapping\Books\Listing();
should be new method call:
// get data from Model
$list = $this->getListing();
And the method:
public function getListing()
{
return new Mapping\Books\Listing();
}
Now you need to mock this method in the controller. And object returned by the mocked method should be your mocked Mapping\Books\Listing object.