【问题标题】:Creating an issue in JIRA using REST API - PHP YII2使用 REST API 在 JIRA 中创建问题 - PHP YII2
【发布时间】:2016-01-20 09:01:04
【问题描述】:

我正在尝试通过我的 PHP YII2 框架在 JIRA 中创建一个问题。 我想要做的是 - 每当我在我的系统中创建一个新版本时,我希望为这个版本自动创建一个问题 JIRA。 我在 CURL 中找到了示例,但到目前为止它不起作用。 我什至没有收到任何错误消息。它在我的系统中创建了一个新版本,但在 JIRA 中没有任何反应,看起来它甚至没有尝试连接到 JIRA。

这是我的 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;
        }
    }
}

非常感谢您的帮助,我不知道还能尝试什么。 提前致谢。

【问题讨论】:

  • 您从 JIRA 返回的错误是什么(该响应的 HTTP 响应代码和正文?)。如果诊断响应没有帮助,为了进一步调试,我建议采用这种方法:捕获用于创建问题的 HTTP POST 的正文,删除所有非必要的详细信息并通过 curl 手动提交,然后添加原始的部分身体直到有东西破裂。如果最小问题 JSON 正文失败,请在此处发布,我会看看。
  • 问题是,我忘了在我原来的帖子中提到它——我没有收到任何错误。没有什么。就我而言,它在我的系统中创建了一个新版本,但 JIRA 没有任何反应,那里没有新问题..

标签: jira-rest-api yii2-basic-app


【解决方案1】:

VersionController.php / actionPostExample() / post_to 中有一个错误。正如所写,我希望向 JIRA 发送 HTTP 帖子会导致 HTTP 404 响应。

这一行:

CURLOPT_URL => JIRA_URL . '/rest/api/latest/' . $resource,

应该是:

CURLOPT_URL => JIRA_URL . '/rest/api/2/' . $resource,

../latest/... 在 JIRA api 文档页面中使用,但它不是其余 API 的一部分。 .../rest/api/2/... 与 JIRA 6 和 7 兼容。

【讨论】:

  • 我修复了它,但没有任何改变,正如我在上面的另一条评论中所说的那样 - 我没有收到任何错误,好像它甚至没有尝试与 JIRA 通信。
  • 我对这个部分有点困惑:
  • $result = curl_exec($ch); 看起来您可以通过调用 Curl.php 中定义的 public function post($url, $raw = true) 来避免一些复杂性。无论哪种情况,如果您在发出请求之前记录一条消息然后记录结果,您可能会更好地了解它在做什么。你应该总是得到某种 HTTP 结果好坏或超时。删除密码也很明显(我不想在它还在的时候引起人们的注意)
  • 我在下面添加了一个'if'函数:$result = curl_exec($ch); ,看看它是否失败,令人惊讶的是我得到了“真实”。这意味着这个功能正在工作,但在 JIRA 中仍然没有新问题。所以如果我没有得到任何回应,这意味着它甚至没有发送任何请求,不是吗?也许我在定义与 JIRA 的连接时遗漏了一些东西?
  • 当使用 CURLOPT_POST => 1,CURLOPT_RETURNTRANSFER => true 时 curl_exec 返回 true(或 1)时,我不是 100% 清楚看看stackoverflow.com/questions/5514139/…。要确认请求是否有效或至少 curl_exec 的行为,请尝试在 URL 中添加明显不正确的内容,以查看错误响应应该是什么。例如CURLOPT_URL => JIRA_URL 。 'BROKEN/rest/api/latest/' 。 $资源,
【解决方案2】:

我做到了。 这是对我有用的功能:

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

在那之后,我不得不在 JSON 中修复几个针对我的项目的东西。

为了便于调试,您可以添加以下内容:

error_reporting(E_ALL);
        ini_set('display_errors', 1);

为了得到明确的错误。

【讨论】:

  • 我们喜欢在我们的开发机器上设置 E_ALL,然后在测试/QA 机器上设置 E_ALL ~E_NOTICE ~E_DEPRICATED。一旦投入生产,只会设置关键和异常。迫使开发人员编写更好的代码,同时防止生产中无用的错误溢出。
猜你喜欢
  • 1970-01-01
  • 2015-11-25
  • 2012-10-20
  • 1970-01-01
  • 2019-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多