PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/Phergie/Event/Request.php

https://github.com/markizano/phergie
PHP | 571 lines | 244 code | 67 blank | 260 comment | 14 complexity | b01cf5484291dabab699bffd1d2b8945 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Phergie
  4. *
  5. * PHP version 5
  6. *
  7. * LICENSE
  8. *
  9. * This source file is subject to the new BSD license that is bundled
  10. * with this package in the file LICENSE.
  11. * It is also available through the world-wide-web at this URL:
  12. * http://phergie.org/license
  13. *
  14. * @category Phergie
  15. * @package Phergie
  16. * @author Phergie Development Team <team@phergie.org>
  17. * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
  18. * @license http://phergie.org/license New BSD License
  19. * @link http://pear.phergie.org/package/Phergie
  20. */
  21. /**
  22. * Autonomous event originating from a user or the server.
  23. *
  24. * @category Phergie
  25. * @package Phergie
  26. * @author Phergie Development Team <team@phergie.org>
  27. * @license http://phergie.org/license New BSD License
  28. * @link http://pear.phergie.org/package/Phergie
  29. * @link http://www.irchelp.org/irchelp/rfc/chapter4.html
  30. */
  31. class Phergie_Event_Request
  32. extends Phergie_Event_Abstract
  33. implements ArrayAccess
  34. {
  35. /**
  36. * Nick message event type
  37. */
  38. const TYPE_NICK = 'nick';
  39. /**
  40. * Whois message event type
  41. */
  42. const TYPE_WHOIS = 'whois';
  43. /**
  44. * Quit command event type
  45. */
  46. const TYPE_QUIT = 'quit';
  47. /**
  48. * Join message event type
  49. */
  50. const TYPE_JOIN = 'join';
  51. /**
  52. * Kick message event type
  53. */
  54. const TYPE_KICK = 'kick';
  55. /**
  56. * Part message event type
  57. */
  58. const TYPE_PART = 'part';
  59. /**
  60. * Invite message event type
  61. */
  62. const TYPE_INVITE = 'invite';
  63. /**
  64. * Mode message event type
  65. */
  66. const TYPE_MODE = 'mode';
  67. /**
  68. * Topic message event type
  69. */
  70. const TYPE_TOPIC = 'topic';
  71. /**
  72. * Private message command event type
  73. */
  74. const TYPE_PRIVMSG = 'privmsg';
  75. /**
  76. * Notice message event type
  77. */
  78. const TYPE_NOTICE = 'notice';
  79. /**
  80. * Pong message event type
  81. */
  82. const TYPE_PONG = 'pong';
  83. /**
  84. * CTCP ACTION command event type
  85. */
  86. const TYPE_ACTION = 'action';
  87. /**
  88. * CTCP PING command event type
  89. */
  90. const TYPE_PING = 'ping';
  91. /**
  92. * CTCP TIME command event type
  93. */
  94. const TYPE_TIME = 'time';
  95. /**
  96. * CTCP VERSION command event type
  97. */
  98. const TYPE_VERSION = 'version';
  99. /**
  100. * CTCP FINGER command event type
  101. */
  102. const TYPE_FINGER = 'finger';
  103. /**
  104. * ERROR message type
  105. */
  106. const TYPE_ERROR = 'error';
  107. /**
  108. * Raw event type
  109. */
  110. const TYPE_RAW = 'raw';
  111. /**
  112. * Mapping of event types to their named parameters
  113. *
  114. * @var array
  115. */
  116. protected static $map = array(
  117. self::TYPE_NICK => array(
  118. 'nickname' => 0
  119. ),
  120. self::TYPE_WHOIS => array(
  121. 'nickmask' => 0
  122. ),
  123. self::TYPE_QUIT => array(
  124. 'message' => 0
  125. ),
  126. self::TYPE_JOIN => array(
  127. 'channel' => 0,
  128. 'keys' => 1
  129. ),
  130. self::TYPE_KICK => array(
  131. 'channel' => 0,
  132. 'user' => 1,
  133. 'comment' => 2
  134. ),
  135. self::TYPE_PART => array(
  136. 'channel' => 0,
  137. 'message' => 1
  138. ),
  139. self::TYPE_INVITE => array(
  140. 'nickname' => 0,
  141. 'channel' => 1
  142. ),
  143. self::TYPE_MODE => array(
  144. 'target' => 0,
  145. 'mode' => 1,
  146. 'limit' => 2,
  147. 'user' => 3,
  148. 'banmask' => 4
  149. ),
  150. self::TYPE_TOPIC => array(
  151. 'channel' => 0,
  152. 'topic' => 1
  153. ),
  154. self::TYPE_PRIVMSG => array(
  155. 'receiver' => 0,
  156. 'text' => 1
  157. ),
  158. self::TYPE_NOTICE => array(
  159. 'nickname' => 0,
  160. 'text' => 1
  161. ),
  162. self::TYPE_PONG => array(
  163. 'server' => 0
  164. ),
  165. self::TYPE_ACTION => array(
  166. 'target' => 0,
  167. 'text' => 1
  168. ),
  169. self::TYPE_PING => array(
  170. 'nick' => 0,
  171. 'hash' => 1
  172. ),
  173. self::TYPE_ERROR => array(
  174. 'message' => 0
  175. ),
  176. self::TYPE_TIME => array(
  177. 'reply' => 0
  178. ),
  179. self::TYPE_VERSION => array(
  180. 'reply' => 0
  181. ),
  182. self::TYPE_FINGER => array(
  183. 'reply' => 0
  184. ),
  185. self::TYPE_RAW => array(
  186. 'message' => 0
  187. ),
  188. );
  189. /**
  190. * Hostmask representing the originating user, if applicable
  191. *
  192. * @var Phergie_Hostmask
  193. */
  194. protected $hostmask;
  195. /**
  196. * Arguments included with the message
  197. *
  198. * @var array
  199. */
  200. protected $arguments = array();
  201. /**
  202. * Raw data sent by the server
  203. *
  204. * @var string
  205. */
  206. protected $rawData;
  207. /**
  208. * Sets the hostmask representing the originating user.
  209. *
  210. * @param Phergie_Hostmask $hostmask User hostmask
  211. *
  212. * @return Phergie_Event_Request Provides a fluent interface
  213. */
  214. public function setHostmask(Phergie_Hostmask $hostmask)
  215. {
  216. $this->hostmask = $hostmask;
  217. return $this;
  218. }
  219. /**
  220. * Returns the hostmask representing the originating user.
  221. *
  222. * @return Phergie_Event_Request|null Hostmask or NULL if none was set
  223. */
  224. public function getHostmask()
  225. {
  226. if (empty($this->hostmask)) {
  227. throw new Phergie_Event_Exception(
  228. 'Hostmask has not been set',
  229. Phergie_Event_Exception::ERR_MISSING_HOSTMASK
  230. );
  231. }
  232. return $this->hostmask;
  233. }
  234. /**
  235. * Sets the arguments for the request.
  236. *
  237. * @param array $arguments Request arguments
  238. *
  239. * @return Phergie_Event_Request Provides a fluent interface
  240. */
  241. public function setArguments(array $arguments)
  242. {
  243. foreach ($arguments as $argument => $value) {
  244. $this->setArgument($argument, $value);
  245. }
  246. return $this;
  247. }
  248. /**
  249. * Sets the value of a single argument for the request.
  250. *
  251. * @param mixed $argument Integer position (starting from 0) or the
  252. * equivalent string name of the argument from self::$map
  253. * @param string $value Value to assign to the argument
  254. *
  255. * @return Phergie_Event_Request Provides a fluent interface
  256. */
  257. public function setArgument($argument, $value)
  258. {
  259. $argument = $this->resolveArgument($argument);
  260. $this->arguments[$argument] = (string) $value;
  261. return $this;
  262. }
  263. /**
  264. * Returns the arguments for the request.
  265. *
  266. * @return array
  267. */
  268. public function getArguments()
  269. {
  270. return $this->arguments;
  271. }
  272. /**
  273. * Removes an argument value from the request.
  274. *
  275. * @param mixed $argument Integer position (starting from 0) or the
  276. * equivalent string name of the argument from self::$map
  277. *
  278. * @return Phergie_Event_Request Provides a fluent interface
  279. */
  280. public function removeArgument($argument)
  281. {
  282. $argument = $this->resolveArgument($argument);
  283. unset($this->arguments[$argument]);
  284. return $this;
  285. }
  286. /**
  287. * Resolves an argument specification to an integer position.
  288. *
  289. * @param mixed $argument Integer position (starting from 0) or the
  290. * equivalent string name of the argument from self::$map
  291. *
  292. * @return int Integer position of the argument
  293. */
  294. protected function resolveArgument($argument)
  295. {
  296. if (isset($this->arguments[$argument])) {
  297. return $argument;
  298. }
  299. if (isset(self::$map[$this->type])) {
  300. if (is_string($argument)) {
  301. $argument = strtolower($argument);
  302. if (isset(self::$map[$this->type][$argument])) {
  303. return self::$map[$this->type][$argument];
  304. }
  305. } else {
  306. if (in_array($argument, self::$map[$this->type])) {
  307. return $argument;
  308. }
  309. }
  310. }
  311. throw new Phergie_Event_Exception(
  312. 'Argument "' . $argument . '" could not be resolved for'
  313. . ' event type "' . $this->type . '"',
  314. Phergie_Event_Exception::ERR_INVALID_ARGUMENT
  315. );
  316. }
  317. /**
  318. * Returns a single specified argument for the request.
  319. *
  320. * @param mixed $argument Integer position (starting from 0) or the
  321. * equivalent string name of the argument from self::$map
  322. *
  323. * @return string|null Argument value or NULL if none is set
  324. */
  325. public function getArgument($argument)
  326. {
  327. $argument = $this->resolveArgument($argument);
  328. if (isset($this->arguments[$argument])) {
  329. return $this->arguments[$argument];
  330. }
  331. return null;
  332. }
  333. /**
  334. * Sets the raw buffer for the event.
  335. *
  336. * @param string $buffer Raw event buffer
  337. *
  338. * @return Phergie_Event_Request Provides a fluent interface
  339. */
  340. public function setRawData($buffer)
  341. {
  342. $this->rawData = $buffer;
  343. return $this;
  344. }
  345. /**
  346. * Returns the raw buffer sent from the server for the event.
  347. *
  348. * @return string
  349. */
  350. public function getRawData()
  351. {
  352. return $this->rawData;
  353. }
  354. /**
  355. * Returns the nick of the user who originated the event.
  356. *
  357. * @return string
  358. */
  359. public function getNick()
  360. {
  361. return $this->getHostmask()->getNick();
  362. }
  363. /**
  364. * Determines whether a given string is a valid IRC channel name.
  365. *
  366. * @param string $string String to analyze
  367. *
  368. * @return bool TRUE if $string contains a valid channel name, FALSE
  369. * otherwise
  370. */
  371. protected function isChannelName($string)
  372. {
  373. // Per the 2000 RFCs 2811 and 2812, channels may begin with &, #, +, or !
  374. return (strspn($string, '#&+!', 0, 1) >= 1);
  375. }
  376. /**
  377. * Returns the channel name if the event occurred in a channel or the
  378. * user nick if the event was a private message directed at the bot by a
  379. * user.
  380. *
  381. * @return string
  382. */
  383. public function getSource()
  384. {
  385. if (!empty($this->arguments[0])
  386. && $this->isChannelName($this->arguments[0])
  387. ) {
  388. return $this->arguments[0];
  389. }
  390. return $this->getHostmask()->getNick();
  391. }
  392. /**
  393. * Returns whether or not the event occurred within a channel.
  394. *
  395. * @return TRUE if the event is in a channel, FALSE otherwise
  396. */
  397. public function isInChannel()
  398. {
  399. return $this->isChannelName($this->getSource());
  400. }
  401. /**
  402. * Returns whether or not the event originated from a user.
  403. *
  404. * @return TRUE if the event is from a user, FALSE otherwise
  405. */
  406. public function isFromUser()
  407. {
  408. $username = $this->getHostmask()->getUsername();
  409. return !empty($username);
  410. }
  411. /**
  412. * Returns whether or not the event originated from the server.
  413. *
  414. * @return TRUE if the event is from the server, FALSE otherwise
  415. */
  416. public function isFromServer()
  417. {
  418. $username = $this->getHostmask()->getUsername();
  419. return empty($username);
  420. }
  421. /**
  422. * Provides access to named parameters via virtual "getter" methods.
  423. *
  424. * @param string $name Name of the method called
  425. * @param array $arguments Arguments passed to the method (should always
  426. * be empty)
  427. *
  428. * @return mixed Method return value
  429. */
  430. public function __call($name, array $arguments)
  431. {
  432. if (!count($arguments) && substr($name, 0, 3) == 'get') {
  433. return $this->getArgument(substr($name, 3));
  434. }
  435. throw new Phergie_Event_Exception(
  436. 'Called invalid method ' . $name . ' in ' . __CLASS__,
  437. Phergie_Event_Exception::ERR_INVALID_METHOD_CALL
  438. );
  439. }
  440. /**
  441. * Checks to see if an event argument is assigned a value.
  442. *
  443. * @param string|int $offset Argument name or position beginning from 0
  444. *
  445. * @return bool TRUE if the argument has a value, FALSE otherwise
  446. * @see ArrayAccess::offsetExists()
  447. */
  448. public function offsetExists($offset)
  449. {
  450. try {
  451. return ($this->getArgument($offset) != null);
  452. } catch (Phergie_Event_Exception $e) {
  453. return false;
  454. }
  455. }
  456. /**
  457. * Returns the value of an event argument.
  458. *
  459. * @param string|int $offset Argument name or position beginning from 0
  460. *
  461. * @return string|null Argument value or NULL if none is set
  462. * @see ArrayAccess::offsetGet()
  463. */
  464. public function offsetGet($offset)
  465. {
  466. return $this->getArgument($offset);
  467. }
  468. /**
  469. * Sets the value of an event argument.
  470. *
  471. * @param string|int $offset Argument name or position beginning from 0
  472. * @param string $value New argument value
  473. *
  474. * @return void
  475. * @see ArrayAccess::offsetSet()
  476. */
  477. public function offsetSet($offset, $value)
  478. {
  479. $this->setArgument($offset, $value);
  480. }
  481. /**
  482. * Removes the value set for an event argument.
  483. *
  484. * @param string|int $offset Argument name or position beginning from 0
  485. *
  486. * @return void
  487. * @see ArrayAccess::offsetUnset()
  488. */
  489. public function offsetUnset($offset)
  490. {
  491. $this->removeArgument($offset);
  492. }
  493. /**
  494. * Returns a mapping of commands to their respective arguments.
  495. *
  496. * @return array Associative array keyed by command referencing an
  497. * associative array keyed by argument name referencing its
  498. * position starting from 0
  499. */
  500. public static function getArgumentMapping()
  501. {
  502. return self::$map;
  503. }
  504. }