Merge branch 'feature/support-multiple-ticket-patterns-10909'

refs #10909
This commit is contained in:
Eric Lippmann 2016-04-13 15:35:22 +02:00
commit 42b7867562
2 changed files with 267 additions and 29 deletions

View File

@ -0,0 +1,152 @@
<?php
/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
namespace Icinga\Application\Hook\Ticket;
use ArrayAccess;
/**
* A ticket pattern
*
* This class should be used by modules which provide implementations for the Web 2 ticket hook.
* Have a look at the GenericTTS module for a possible use case.
*/
class TicketPattern implements ArrayAccess
{
/**
* The result of a performed ticket match
*
* @var array
*/
protected $match = array();
/**
* The name of the TTS integration
*
* @var string
*/
protected $name;
/**
* The ticket pattern
*
* @var string
*/
protected $pattern;
/**
* {@inheritdoc}
*/
public function offsetExists($offset)
{
return isset($this->match[$offset]);
}
/**
* {@inheritdoc}
*/
public function offsetGet($offset)
{
return array_key_exists($offset, $this->match) ? $this->match[$offset] : null;
}
/**
* {@inheritdoc}
*/
public function offsetSet($offset, $value)
{
if ($offset === null) {
$this->match[] = $value;
} else {
$this->match[$offset] = $value;
}
}
/**
* {@inheritdoc}
*/
public function offsetUnset($offset)
{
unset($this->match[$offset]);
}
/**
* Get the result of a performed ticket match
*
* @return array
*/
public function getMatch()
{
return $this->match;
}
/**
* Set the result of a performed ticket match
*
* @param array $match
*
* @return $this
*/
public function setMatch(array $match)
{
$this->match = $match;
return $this;
}
/**
* Get the name of the TTS integration
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set the name of the TTS integration
*
* @param string $name
*
* @return $this
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get the ticket pattern
*
* @return string
*/
public function getPattern()
{
return $this->pattern;
}
/**
* Set the ticket pattern
*
* @param string $pattern
*
* @return $this
*/
public function setPattern($pattern)
{
$this->pattern = $pattern;
return $this;
}
/**
* Whether the integration is properly configured, i.e. the pattern and the URL are not empty
*
* @return bool
*/
public function isValid()
{
return ! empty($this->pattern);
}
}

View File

@ -3,15 +3,17 @@
namespace Icinga\Application\Hook;
use ArrayIterator;
use ErrorException;
use Exception;
use Icinga\Application\Hook\Ticket\TicketPattern;
use Icinga\Application\Logger;
use Icinga\Exception\IcingaException;
/**
* Base class for ticket hooks
*
* Extend this class if you want to integrate your ticketing solution Icinga Web 2
* Extend this class if you want to integrate your ticketing solution into Icinga Web 2.
*/
abstract class TicketHook
{
@ -39,6 +41,100 @@ abstract class TicketHook
{
}
/**
* Create a link for each matched element in the subject text
*
* @param array|TicketPattern $match Matched element according to {@link getPattern()}
*
* @return string Replacement string
*/
abstract public function createLink($match);
/**
* Get the pattern(s) to search for
*
* Return an array of TicketPattern instances here to support multiple TTS integrations.
*
* @return string|TicketPattern[]
*/
abstract public function getPattern();
/**
* Apply ticket patterns to the given text
*
* @param string $text
* @param TicketPattern[] $ticketPatterns
*
* @return string
*/
private function applyTicketPatterns($text, array $ticketPatterns)
{
$out = '';
$start = 0;
$iterator = new ArrayIterator($ticketPatterns);
$iterator->rewind();
while ($iterator->valid()) {
$ticketPattern = $iterator->current();
try {
preg_match($ticketPattern->getPattern(), $text, $match, PREG_OFFSET_CAPTURE, $start);
} catch (ErrorException $e) {
$this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e));
$iterator->next();
continue;
}
if (empty($match)) {
$iterator->next();
continue;
}
// Remove preg_offset from match for the ticket pattern
$carry = array();
array_walk($match, function ($value, $key) use (&$carry) {
$carry[$key] = $value[0];
}, $carry);
$ticketPattern->setMatch($carry);
$offsetLeft = $match[0][1];
$matchLength = strlen($match[0][0]);
$out .= substr($text, $start, $offsetLeft - $start);
try {
$out .= $this->createLink($ticketPattern);
} catch (Exception $e) {
$this->fail('Can\'t create ticket links: %s', IcingaException::describe($e));
return $text;
}
$start = $offsetLeft + $matchLength;
}
$out .= substr($text, $start);
return $out;
}
/**
* Helper function to create a TicketPattern instance
*
* @param string $name Name of the TTS integration
* @param string $pattern Ticket pattern
*
* @return TicketPattern
*/
protected function createTicketPattern($name, $pattern)
{
$ticketPattern = new TicketPattern();
$ticketPattern
->setName($name)
->setPattern($pattern);
return $ticketPattern;
}
/**
* Set the hook as failed w/ the given message
*
@ -63,22 +159,6 @@ abstract class TicketHook
return $this->lastError;
}
/**
* Get the pattern
*
* @return string
*/
abstract public function getPattern();
/**
* Create a link for each matched element in the subject text
*
* @param array $match Array of matched elements according to {@link getPattern()}
*
* @return string Replacement string
*/
abstract public function createLink($match);
/**
* Create links w/ {@link createLink()} in the given text that matches to the subject from {@link getPattern()}
*
@ -101,22 +181,28 @@ abstract class TicketHook
$this->fail('Can\'t create ticket links: Retrieving the pattern failed: %s', IcingaException::describe($e));
return $text;
}
if (empty($pattern)) {
$this->fail('Can\'t create ticket links: Pattern is empty');
return $text;
}
try {
$text = preg_replace_callback(
$pattern,
array($this, 'createLink'),
$text
);
} catch (ErrorException $e) {
$this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e));
return $text;
} catch (Exception $e) {
$this->fail('Can\'t create ticket links: %s', IcingaException::describe($e));
return $text;
if (is_array($pattern)) {
$text = $this->applyTicketPatterns($text, $pattern);
} else {
try {
$text = preg_replace_callback(
$pattern,
array($this, 'createLink'),
$text
);
} catch (ErrorException $e) {
$this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e));
return $text;
} catch (Exception $e) {
$this->fail('Can\'t create ticket links: %s', IcingaException::describe($e));
return $text;
}
}
return $text;