Commit ff00441f68d4082337dc7ce8025f2a5bb6169e19

Authored by kevin_fourie
1 parent 37c12a11

Merged in from DEV trunk...

"KTS-2113"
"Split KTAPI into seperate files based on classes"
Implemented.

Reviewed By: Kevin Fourie

"KTS-2114"
"kt3template.inc.php did not find the PluginRegistry."
Fixed. Added require_once statement.

Reviewed By: Kevin Fourie

"KTS-2116"
"Document object does var_dump() on pear error."
Fixed.

Reviewed By: Kevin Fourie

"KTS-2117"
"upgrade simpletest"
Upgraded.

Reviewed By: Kevin Fourie

"KTS-2118"
"FolderUtil allows duplicate folders to be added"
Fixed.

Reviewed By: Kevin Fourie

"KTS-2115"
"create unit tests for ktapi"
Fixed.

Reviewed By: Kevin Fourie

"KTS-2115"
"create unit tests for ktapi"
Implemented. Some basic unit tests for the KTAPI have been implemented.

Reviewed By: Kevin Fourie

"KTS-2119"
"Error message in upload.php: "get_session() should be overloaded!"
Fixed.

Reviewed By: Kevin Fourie



git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/STABLE/trunk@6814 c91229c3-7414-0410-bfa2-8a42b809f60b
Showing 36 changed files with 3639 additions and 2630 deletions
ktapi/KTAPIConstants.inc.php 0 → 100644
  1 +<?
  2 +
  3 +/**
  4 + *
  5 + * The contents of this file are subject to the KnowledgeTree Public
  6 + * License Version 1.1.2 ("License"); You may not use this file except in
  7 + * compliance with the License. You may obtain a copy of the License at
  8 + * http://www.knowledgetree.com/KPL
  9 + *
  10 + * Software distributed under the License is distributed on an "AS IS"
  11 + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
  12 + * See the License for the specific language governing rights and
  13 + * limitations under the License.
  14 + *
  15 + * All copies of the Covered Code must include on each user interface screen:
  16 + * (i) the "Powered by KnowledgeTree" logo and
  17 + * (ii) the KnowledgeTree copyright notice
  18 + * in the same form as they appear in the distribution. See the License for
  19 + * requirements.
  20 + *
  21 + * The Original Code is: KnowledgeTree Open Source
  22 + *
  23 + * The Initial Developer of the Original Code is The Jam Warehouse Software
  24 + * (Pty) Ltd, trading as KnowledgeTree.
  25 + * Portions created by The Jam Warehouse Software (Pty) Ltd are Copyright
  26 + * (C) 2007 The Jam Warehouse Software (Pty) Ltd;
  27 + * All Rights Reserved.
  28 + * Contributor( s): ______________________________________
  29 + *
  30 + */
  31 +
  32 +require_once('../config/dmsDefaults.php');
  33 +require_once(KT_LIB_DIR . '/filelike/fsfilelike.inc.php');
  34 +require_once(KT_LIB_DIR . '/foldermanagement/folderutil.inc.php');
  35 +
  36 +// Generic error messages used in the API. There may be some others specific to functionality
  37 +// directly in the code.
  38 +// TODO: Check that they are all relevant.
  39 +
  40 +define('KTAPI_ERROR_SESSION_INVALID', 'The session could not be resolved.');
  41 +define('KTAPI_ERROR_PERMISSION_INVALID', 'The permission could not be resolved.');
  42 +define('KTAPI_ERROR_FOLDER_INVALID', 'The folder could not be resolved.');
  43 +define('KTAPI_ERROR_DOCUMENT_INVALID', 'The document could not be resolved.');
  44 +define('KTAPI_ERROR_USER_INVALID', 'The user could not be resolved.');
  45 +define('KTAPI_ERROR_KTAPI_INVALID', 'The ktapi could not be resolved.');
  46 +define('KTAPI_ERROR_INSUFFICIENT_PERMISSIONS', 'The user does not have sufficient permissions to access the resource.');
  47 +define('KTAPI_ERROR_INTERNAL_ERROR', 'An internal error occurred. Please review the logs.');
  48 +define('KTAPI_ERROR_DOCUMENT_TYPE_INVALID', 'The document type could not be resolved.');
  49 +define('KTAPI_ERROR_DOCUMENT_CHECKED_OUT', 'The document is checked out.');
  50 +define('KTAPI_ERROR_DOCUMENT_NOT_CHECKED_OUT', 'The document is not checked out.');
  51 +define('KTAPI_ERROR_WORKFLOW_INVALID', 'The workflow could not be resolved.');
  52 +define('KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS', 'The workflow is not in progress.');
  53 +
  54 +// Mapping of permissions to actions.
  55 +// TODO: Check that they are all correct.
  56 +// Note, currently, all core actions have permissions that are defined in the plugins.
  57 +// As the permissions are currently associated with actions which are quite closely linked
  58 +// to the web interface, it is not the nicest way to do things. They should be associated at
  59 +// a lower level, such as in the api. probably, better, would be at some stage to assocate
  60 +// the permissions to the action/transaction in the database so administrators can really customise
  61 +// as required.
  62 +
  63 +define('KTAPI_PERMISSION_DELETE', 'ktcore.permissions.delete');
  64 +define('KTAPI_PERMISSION_READ', 'ktcore.permissions.read');
  65 +define('KTAPI_PERMISSION_WRITE', 'ktcore.permissions.write');
  66 +define('KTAPI_PERMISSION_ADD_FOLDER', 'ktcore.permissions.addFolder');
  67 +define('KTAPI_PERMISSION_RENAME_FOLDER', 'ktcore.permissions.folder_rename');
  68 +define('KTAPI_PERMISSION_CHANGE_OWNERSHIP', 'ktcore.permissions.security');
  69 +define('KTAPI_PERMISSION_DOCUMENT_MOVE', 'ktcore.permissions.write');
  70 +define('KTAPI_PERMISSION_WORKFLOW', 'ktcore.permissions.workflow');
  71 +
  72 +?>
0 \ No newline at end of file 73 \ No newline at end of file
ktapi/KTAPIDocument.inc.php 0 → 100644
  1 +<?
  2 +class KTAPI_Document extends KTAPI_FolderItem
  3 +{
  4 + /**
  5 + * This is a reference to the internal document object.
  6 + *
  7 + * @var Document
  8 + */
  9 + var $document;
  10 + /**
  11 + * This is the id of the document.
  12 + *
  13 + * @var int
  14 + */
  15 + var $documentid;
  16 + /**
  17 + * This is a reference to the parent folder.
  18 + *
  19 + * @var KTAPI_Folder
  20 + */
  21 + var $ktapi_folder;
  22 +
  23 + function get_documentid()
  24 + {
  25 + return $this->documentid;
  26 + }
  27 +
  28 + /**
  29 + * This is used to get a document based on document id.
  30 + *
  31 + * @static
  32 + * @access public
  33 + * @param KTAPI $ktapi
  34 + * @param int $documentid
  35 + * @return KTAPI_Document
  36 + */
  37 + function &get(&$ktapi, $documentid)
  38 + {
  39 + assert(!is_null($ktapi));
  40 + assert(is_a($ktapi, 'KTAPI'));
  41 + assert(is_numeric($documentid));
  42 +
  43 + $documentid += 0;
  44 +
  45 + $document = &Document::get($documentid);
  46 + if (is_null($document) || PEAR::isError($document))
  47 + {
  48 + return new KTAPI_Error(KTAPI_ERROR_DOCUMENT_INVALID,$document );
  49 + }
  50 +
  51 + $user = $ktapi->can_user_access_object_requiring_permission($document, KTAPI_PERMISSION_READ);
  52 +
  53 + if (is_null($user) || PEAR::isError($user))
  54 + {
  55 + return $user;
  56 + }
  57 +
  58 + $folderid = $document->getParentID();
  59 +
  60 + if (!is_null($folderid))
  61 + {
  62 + $ktapi_folder = &KTAPI_Folder::get($ktapi, $folderid);
  63 + }
  64 + else
  65 + {
  66 + $ktapi_folder = null;
  67 + }
  68 + // We don't do any checks on this folder as it could possibly be deleted, and is not required right now.
  69 +
  70 + return new KTAPI_Document($ktapi, $ktapi_folder, $document);
  71 + }
  72 +
  73 + function is_deleted()
  74 + {
  75 + return ($this->document->getStatusID() == 3);
  76 + }
  77 +
  78 + /**
  79 + * This is the constructor for the KTAPI_Folder.
  80 + *
  81 + * @access private
  82 + * @param KTAPI $ktapi
  83 + * @param Document $document
  84 + * @return KTAPI_Document
  85 + */
  86 + function KTAPI_Document(&$ktapi, &$ktapi_folder, &$document)
  87 + {
  88 + assert(is_a($ktapi,'KTAPI'));
  89 + assert(is_null($ktapi_folder) || is_a($ktapi_folder,'KTAPI_Folder'));
  90 +
  91 + $this->ktapi = &$ktapi;
  92 + $this->ktapi_folder = &$ktapi_folder;
  93 + $this->document = &$document;
  94 + $this->documentid = $document->getId();
  95 + }
  96 +
  97 + /**
  98 + * This checks a document into the repository
  99 + *
  100 + * @param string $filename
  101 + * @param string $reason
  102 + * @param string $tempfilename
  103 + * @param bool $major_update
  104 + */
  105 + function checkin($filename, $reason, $tempfilename, $major_update=false)
  106 + {
  107 + if (!is_file($tempfilename))
  108 + {
  109 + return new PEAR_Error('File does not exist.');
  110 + }
  111 +
  112 + $user = $this->can_user_access_object_requiring_permission($this->document, KTAPI_PERMISSION_WRITE);
  113 +
  114 + if (PEAR::isError($user))
  115 + {
  116 + return $user;
  117 + }
  118 +
  119 + if (!$this->document->getIsCheckedOut())
  120 + {
  121 + return new PEAR_Error(KTAPI_ERROR_DOCUMENT_NOT_CHECKED_OUT);
  122 + }
  123 +
  124 + $options = array('major_update'=>$major_update);
  125 +
  126 + $currentfilename = $this->document->getFileName();
  127 + if ($filename != $currentfilename)
  128 + {
  129 + $options['newfilename'] = $filename;
  130 + }
  131 +
  132 + DBUtil::startTransaction();
  133 + $result = KTDocumentUtil::checkin($this->document, $tempfilename, $reason, $user, $options);
  134 +
  135 + if (PEAR::isError($result))
  136 + {
  137 + DBUtil::rollback();
  138 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$result);
  139 + }
  140 + DBUtil::commit();
  141 +
  142 + $tempfilename=addslashes($tempfilename);
  143 + $sql = "DELETE FROM uploaded_files WHERE tempfilename='$tempfilename'";
  144 + $result = DBUtil::runQuery($sql);
  145 + if (PEAR::isError($result))
  146 + {
  147 + return $result;
  148 + }
  149 +
  150 + }
  151 +
  152 +
  153 + function is_checked_out()
  154 + {
  155 + return ($this->document->getIsCheckedOut());
  156 + }
  157 +
  158 + /**
  159 + * This reverses the checkout process.
  160 + *
  161 + * @param string $reason
  162 + */
  163 + function undo_checkout($reason)
  164 + {
  165 + $user = $this->can_user_access_object_requiring_permission($this->document, KTAPI_PERMISSION_WRITE);
  166 +
  167 + if (PEAR::isError($user))
  168 + {
  169 + return $user;
  170 + }
  171 +
  172 + if (!$this->document->getIsCheckedOut())
  173 + {
  174 + return new PEAR_Error(KTAPI_ERROR_DOCUMENT_NOT_CHECKED_OUT);
  175 + }
  176 +
  177 + DBUtil::startTransaction();
  178 +
  179 + $this->document->setIsCheckedOut(0);
  180 + $this->document->setCheckedOutUserID(-1);
  181 + $res = $this->document->update();
  182 + if (($res === false) || PEAR::isError($res))
  183 + {
  184 + DBUtil::rollback();
  185 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res);
  186 + }
  187 +
  188 + $oDocumentTransaction = & new DocumentTransaction($this->document, $reason, 'ktcore.transactions.force_checkin');
  189 +
  190 + $res = $oDocumentTransaction->create();
  191 + if (($res === false) || PEAR::isError($res)) {
  192 + DBUtil::rollback();
  193 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res);
  194 + }
  195 + DBUtil::commit();
  196 + }
  197 +
  198 + /**
  199 + * This returns a URL to the file that can be downloaded.
  200 + *
  201 + * @param string $reason
  202 + */
  203 + function checkout($reason)
  204 + {
  205 + $user = $this->can_user_access_object_requiring_permission($this->document, KTAPI_PERMISSION_WRITE);
  206 +
  207 + if (PEAR::isError($user))
  208 + {
  209 + return $user;
  210 + }
  211 +
  212 + if ($this->document->getIsCheckedOut())
  213 + {
  214 + return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT);
  215 + }
  216 +
  217 + DBUtil::startTransaction();
  218 + $res = KTDocumentUtil::checkout($this->document, $reason, $user);
  219 + if (PEAR::isError($res))
  220 + {
  221 + DBUtil::rollback();
  222 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res);
  223 + }
  224 +
  225 + DBUtil::commit();
  226 + }
  227 +
  228 + /**
  229 + * This deletes a document from the folder.
  230 + *
  231 + * @param string $reason
  232 + */
  233 + function delete($reason)
  234 + {
  235 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_DELETE);
  236 +
  237 + if (PEAR::isError($user))
  238 + {
  239 + return $user;
  240 + }
  241 +
  242 + if ($this->document->getIsCheckedOut())
  243 + {
  244 + return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT);
  245 + }
  246 +
  247 + DBUtil::startTransaction();
  248 + $res = KTDocumentUtil::delete($this->document, $reason);
  249 + if (PEAR::isError($res))
  250 + {
  251 + DBUtil::rollback();
  252 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res);
  253 + }
  254 +
  255 + DBUtil::commit();
  256 + }
  257 +
  258 + /**
  259 + * This changes the owner of the file.
  260 + *
  261 + * @param string $ktapi_newuser
  262 + */
  263 + function change_owner($newusername, $reason='Changing of owner.')
  264 + {
  265 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_CHANGE_OWNERSHIP);
  266 +
  267 + if (PEAR::isError($user))
  268 + {
  269 + return $user;
  270 + }
  271 +
  272 + DBUtil::startTransaction();
  273 +
  274 + $user = &User::getByUserName($newusername);
  275 + if (is_null($user) || PEAR::isError($user))
  276 + {
  277 + return new KTAPI_Error('User could not be found',$user);
  278 + }
  279 +
  280 + $newuserid = $user->getId();
  281 +
  282 + $this->document->setOwnerID($newuserid);
  283 +
  284 + $res = $this->document->update();
  285 +
  286 + if (PEAR::isError($res))
  287 + {
  288 + DBUtil::rollback();
  289 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR ,$res );
  290 + }
  291 +
  292 + $res = KTPermissionUtil::updatePermissionLookup($this->document);
  293 + if (PEAR::isError($res))
  294 + {
  295 + DBUtil::rollback();
  296 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res );
  297 + }
  298 +
  299 + $oDocumentTransaction = & new DocumentTransaction($this->document, $reason, 'ktcore.transactions.permissions_change');
  300 +
  301 + $res = $oDocumentTransaction->create();
  302 + if (($res === false) || PEAR::isError($res)) {
  303 + DBUtil::rollback();
  304 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res );
  305 + }
  306 +
  307 + DBUtil::commit();
  308 + }
  309 +
  310 + /**
  311 + * This copies the document to another folder.
  312 + *
  313 + * @param KTAPI_Folder $ktapi_target_folder
  314 + * @param string $reason
  315 + * @param string $newname
  316 + * @param string $newfilename
  317 + */
  318 + function copy(&$ktapi_target_folder, $reason, $newname=null, $newfilename=null)
  319 + {
  320 + assert(!is_null($ktapi_target_folder));
  321 + assert(is_a($ktapi_target_folder,'KTAPI_Folder'));
  322 +
  323 + if (empty($newname))
  324 + {
  325 + $newname=null;
  326 + }
  327 + if (empty($newfilename))
  328 + {
  329 + $newfilename=null;
  330 + }
  331 +
  332 + $user = $this->ktapi->get_user();
  333 +
  334 + if ($this->document->getIsCheckedOut())
  335 + {
  336 + return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT);
  337 + }
  338 +
  339 + $target_folder = &$ktapi_target_folder->get_folder();
  340 +
  341 + $result = $this->can_user_access_object_requiring_permission( $target_folder, KTAPI_PERMISSION_WRITE);
  342 +
  343 + if (PEAR::isError($result))
  344 + {
  345 + return $result;
  346 + }
  347 +
  348 + $name = $this->document->getName();
  349 + $clash = KTDocumentUtil::nameExists($target_folder, $name);
  350 + if ($clash && !is_null($newname))
  351 + {
  352 + $name = $newname;
  353 + $clash = KTDocumentUtil::nameExists($target_folder, $name);
  354 + }
  355 + if ($clash)
  356 + {
  357 + return new PEAR_Error('A document with this title already exists in your chosen folder. Please choose a different folder, or specify a new title for the copied document.');
  358 + }
  359 +
  360 + $filename=$this->document->getFilename();
  361 + $clash = KTDocumentUtil::fileExists($target_folder, $filename);
  362 +
  363 + if ($clash && !is_null($newname))
  364 + {
  365 + $filename = $newfilename;
  366 + $clash = KTDocumentUtil::fileExists($target_folder, $filename);
  367 + }
  368 + if ($clash)
  369 + {
  370 + return new PEAR_Error('A document with this filename already exists in your chosen folder. Please choose a different folder, or specify a new filename for the copied document.');
  371 + }
  372 +
  373 + DBUtil::startTransaction();
  374 +
  375 + $new_document = KTDocumentUtil::copy($this->document, $target_folder, $reason);
  376 + if (PEAR::isError($new_document))
  377 + {
  378 + DBUtil::rollback();
  379 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$new_document );
  380 + }
  381 +
  382 + $new_document->setName($name);
  383 + $new_document->setFilename($filename);
  384 +
  385 + $res = $new_document->update();
  386 +
  387 + if (PEAR::isError($res))
  388 + {
  389 + DBUtil::rollback();
  390 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res );
  391 + }
  392 +
  393 + DBUtil::commit();
  394 +
  395 + // FIXME do we need to refactor all trigger usage into the util function?
  396 + $oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
  397 + $aTriggers = $oKTTriggerRegistry->getTriggers('copyDocument', 'postValidate');
  398 + foreach ($aTriggers as $aTrigger) {
  399 + $sTrigger = $aTrigger[0];
  400 + $oTrigger = new $sTrigger;
  401 + $aInfo = array(
  402 + 'document' => $new_document,
  403 + 'old_folder' => $this->folder->get_folder(),
  404 + 'new_folder' => $target_folder,
  405 + );
  406 + $oTrigger->setInfo($aInfo);
  407 + $ret = $oTrigger->postValidate();
  408 + }
  409 + }
  410 +
  411 + /**
  412 + * This moves the document to another folder.
  413 + *
  414 + * @param KTAPI_Folder $ktapi_target_folder
  415 + * @param string $reason
  416 + * @param string $newname
  417 + * @param string $newfilename
  418 + */
  419 + function move(&$ktapi_target_folder, $reason, $newname=null, $newfilename=null)
  420 + {
  421 + assert(!is_null($ktapi_target_folder));
  422 + assert(is_a($ktapi_target_folder,'KTAPI_Folder'));
  423 +
  424 + if (empty($newname))
  425 + {
  426 + $newname=null;
  427 + }
  428 + if (empty($newfilename))
  429 + {
  430 + $newfilename=null;
  431 + }
  432 +
  433 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_DOCUMENT_MOVE);
  434 +
  435 + if (PEAR::isError($user))
  436 + {
  437 + return $user;
  438 + }
  439 +
  440 + if ($this->document->getIsCheckedOut())
  441 + {
  442 + return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT);
  443 + }
  444 +
  445 + $target_folder = $ktapi_target_folder->get_folder();
  446 +
  447 + $result= $this->can_user_access_object_requiring_permission( $target_folder, KTAPI_PERMISSION_WRITE);
  448 +
  449 + if (PEAR::isError($result))
  450 + {
  451 + return $result;
  452 + }
  453 +
  454 + if (!KTDocumentUtil::canBeMoved($this->document))
  455 + {
  456 + return new PEAR_Error('Document cannot be moved.');
  457 + }
  458 +
  459 + $name = $this->document->getName();
  460 + $clash = KTDocumentUtil::nameExists($target_folder, $name);
  461 + if ($clash && !is_null($newname))
  462 + {
  463 + $name = $newname;
  464 + $clash = KTDocumentUtil::nameExists($target_folder, $name);
  465 + }
  466 + if ($clash)
  467 + {
  468 + return new PEAR_Error('A document with this title already exists in your chosen folder. Please choose a different folder, or specify a new title for the moved document.');
  469 + }
  470 +
  471 + $filename=$this->document->getFilename();
  472 + $clash = KTDocumentUtil::fileExists($target_folder, $filename);
  473 +
  474 + if ($clash && !is_null($newname))
  475 + {
  476 + $filename = $newfilename;
  477 + $clash = KTDocumentUtil::fileExists($target_folder, $filename);
  478 + }
  479 + if ($clash)
  480 + {
  481 + return new PEAR_Error('A document with this filename already exists in your chosen folder. Please choose a different folder, or specify a new filename for the moved document.');
  482 + }
  483 +
  484 + DBUtil::startTransaction();
  485 +
  486 + $res = KTDocumentUtil::move($this->document, $target_folder, $user, $reason);
  487 + if (PEAR::isError($res))
  488 + {
  489 + DBUtil::rollback();
  490 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res );
  491 + }
  492 +
  493 + $this->document->setName($name);
  494 + $this->document->setFilename($filename);
  495 +
  496 + $res = $this->document->update();
  497 +
  498 + if (PEAR::isError($res))
  499 + {
  500 + DBUtil::rollback();
  501 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res );
  502 + }
  503 +
  504 + DBUtil::commit();
  505 + }
  506 +
  507 + /**
  508 + * This changes the filename of the document.
  509 + *
  510 + * @param string $newname
  511 + */
  512 + function renameFile($newname)
  513 + {
  514 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE);
  515 +
  516 + if (PEAR::isError($user))
  517 + {
  518 + return $user;
  519 + }
  520 +
  521 + DBUtil::startTransaction();
  522 + $res = KTDocumentUtil::rename($this->document, $newname, $user);
  523 + if (PEAR::isError($res))
  524 + {
  525 + DBUtil::rollback();
  526 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res );
  527 + }
  528 + DBUtil::commit();
  529 + }
  530 +
  531 + /**
  532 + * This changes the document type of the document.
  533 + *
  534 + * @param string $newname
  535 + */
  536 + function change_document_type($documenttype)
  537 + {
  538 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE);
  539 +
  540 + if (PEAR::isError($user))
  541 + {
  542 + return $user;
  543 + }
  544 +
  545 + $doctypeid = KTAPI::get_documenttypeid($documenttype);
  546 +
  547 + if ($this->document->getDocumentTypeId() != $doctypeid)
  548 + {
  549 + DBUtil::startTransaction();
  550 + $this->document->setDocumentTypeId($doctypeid);
  551 + $res = $this->document->update();
  552 +
  553 + if (PEAR::isError($res))
  554 + {
  555 + DBUtil::rollback();
  556 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res );
  557 + }
  558 + DBUtil::commit();
  559 + }
  560 + }
  561 +
  562 + /**
  563 + * This changes the title of the document.
  564 + *
  565 + * @param string $newname
  566 + */
  567 + function rename($newname)
  568 + {
  569 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE);
  570 +
  571 + if (PEAR::isError($user))
  572 + {
  573 + return $user;
  574 + }
  575 +
  576 + if ($this->document->getName() != $newname)
  577 + {
  578 +
  579 + DBUtil::startTransaction();
  580 + $this->document->setName($newname);
  581 + $res = $this->document->update();
  582 +
  583 + if (PEAR::isError($res))
  584 + {
  585 + DBUtil::rollback();
  586 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res);
  587 + }
  588 + DBUtil::commit();
  589 + }
  590 + }
  591 +
  592 + /**
  593 + * This flags the document as 'archived'.
  594 + *
  595 + * @param string $reason
  596 + */
  597 + function archive($reason)
  598 + {
  599 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE);
  600 +
  601 + if (PEAR::isError($user))
  602 + {
  603 + return $user;
  604 + }
  605 +
  606 + list($permission, $user) = $perm_and_user;
  607 +
  608 + DBUtil::startTransaction();
  609 + $this->document->setStatusID(ARCHIVED);
  610 + $res = $this->document->update();
  611 + if (($res === false) || PEAR::isError($res)) {
  612 + DBUtil::rollback();
  613 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res);
  614 + }
  615 +
  616 + $oDocumentTransaction = & new DocumentTransaction($this->document, sprintf(_kt('Document archived: %s'), $reason), 'ktcore.transactions.update');
  617 + $oDocumentTransaction->create();
  618 +
  619 + DBUtil::commit();
  620 +
  621 + $oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
  622 + $aTriggers = $oKTTriggerRegistry->getTriggers('archive', 'postValidate');
  623 + foreach ($aTriggers as $aTrigger)
  624 + {
  625 + $sTrigger = $aTrigger[0];
  626 + $oTrigger = new $sTrigger;
  627 + $aInfo = array(
  628 + 'document' => $this->document,
  629 + );
  630 + $oTrigger->setInfo($aInfo);
  631 + $ret = $oTrigger->postValidate();
  632 + }
  633 + }
  634 +
  635 + /**
  636 + * This starts a workflow on a document.
  637 + *
  638 + * @param string $workflow
  639 + */
  640 + function start_workflow($workflow)
  641 + {
  642 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW);
  643 +
  644 + if (PEAR::isError($user))
  645 + {
  646 + return $user;
  647 + }
  648 +
  649 + $workflowid = $this->document->getWorkflowId();
  650 +
  651 + if (!empty($workflowid))
  652 + {
  653 + return new PEAR_Error('A workflow is already defined.');
  654 + }
  655 +
  656 + $workflow = KTWorkflow::getByName($workflow);
  657 + if (is_null($workflow) || PEAR::isError($workflow))
  658 + {
  659 + return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID, $workflow);
  660 + }
  661 +
  662 + DBUtil::startTransaction();
  663 + $result = KTWorkflowUtil::startWorkflowOnDocument($workflow, $this->document);
  664 + if (is_null($result) || PEAR::isError($result))
  665 + {
  666 + DBUtil::rollback();
  667 + return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID, $result);
  668 + }
  669 + DBUtil::commit();
  670 + }
  671 +
  672 + /**
  673 + * This deletes the workflow on the document.
  674 + *
  675 + */
  676 + function delete_workflow()
  677 + {
  678 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW);
  679 +
  680 + if (PEAR::isError($user))
  681 + {
  682 + return $user;
  683 + }
  684 +
  685 + $workflowid=$this->document->getWorkflowId();
  686 + if (!empty($workflowid))
  687 + {
  688 + return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS);
  689 + }
  690 +
  691 + DBUtil::startTransaction();
  692 + $result = KTWorkflowUtil::startWorkflowOnDocument(null, $this->document);
  693 + if (is_null($result) || PEAR::isError($result))
  694 + {
  695 + DBUtil::rollback();
  696 + return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID,$result);
  697 + }
  698 + DBUtil::commit();
  699 + }
  700 +
  701 + /**
  702 + * This performs a transition on the workflow
  703 + *
  704 + * @param string $transition
  705 + * @param string $reason
  706 + */
  707 + function perform_workflow_transition($transition, $reason)
  708 + {
  709 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW);
  710 +
  711 + if (PEAR::isError($user))
  712 + {
  713 + return $user;
  714 + }
  715 +
  716 + $workflowid=$this->document->getWorkflowId();
  717 + if (empty($workflowid))
  718 + {
  719 + return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS);
  720 + }
  721 +
  722 + $transition = &KTWorkflowTransition::getByName($transition);
  723 + if (is_null($transition) || PEAR::isError($transition))
  724 + {
  725 + return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID, $transition);
  726 + }
  727 +
  728 + DBUtil::startTransaction();
  729 + $result = KTWorkflowUtil::performTransitionOnDocument($transition, $this->document, $user, $reason);
  730 + if (is_null($result) || PEAR::isError($result))
  731 + {
  732 + DBUtil::rollback();
  733 + return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID, $transition);
  734 + }
  735 + DBUtil::commit();
  736 + }
  737 +
  738 +
  739 +
  740 + /**
  741 + * This returns all metadata for the document.
  742 + *
  743 + * @return array
  744 + */
  745 + function get_metadata()
  746 + {
  747 + $doctypeid = $this->document->getDocumentTypeID();
  748 + $fieldsets = (array) KTMetadataUtil::fieldsetsForDocument($this->document, $doctypeid);
  749 +
  750 + $results = array();
  751 +
  752 + foreach ($fieldsets as $fieldset)
  753 + {
  754 + if ($fieldset->getIsConditional()) { /* this is not implemented...*/ continue; }
  755 +
  756 + $fields = $fieldset->getFields();
  757 + $result = array('fieldset' => $fieldset->getName(),
  758 + 'description' => $fieldset->getDescription());
  759 +
  760 + $fieldsresult = array();
  761 +
  762 + foreach ($fields as $field)
  763 + {
  764 + $value = 'n/a';
  765 +
  766 + $fieldvalue = DocumentFieldLink::getByDocumentAndField($this->document, $field);
  767 + if (!is_null($fieldvalue) && (!PEAR::isError($fieldvalue)))
  768 + {
  769 + $value = $fieldvalue->getValue();
  770 + }
  771 +
  772 + $controltype = 'string';
  773 + if ($field->getHasLookup())
  774 + {
  775 + $controltype = 'lookup';
  776 + if ($field->getHasLookupTree())
  777 + {
  778 + $controltype = 'tree';
  779 + }
  780 + }
  781 +
  782 + switch ($controltype)
  783 + {
  784 + case 'lookup':
  785 + $selection = KTAPI::get_metadata_lookup($field->getId());
  786 + break;
  787 + case 'tree':
  788 + $selection = KTAPI::get_metadata_tree($field->getId());
  789 + break;
  790 + default:
  791 + $selection= array();
  792 + }
  793 +
  794 +
  795 + $fieldsresult[] = array(
  796 + 'name' => $field->getName(),
  797 + 'required' => $field->getIsMandatory(),
  798 + 'value' => $value,
  799 + 'description' => $field->getDescription(),
  800 + 'control_type' => $controltype,
  801 + 'selection' => $selection
  802 +
  803 + );
  804 +
  805 + }
  806 + $result['fields'] = $fieldsresult;
  807 + $results [] = $result;
  808 + }
  809 +
  810 + return $results;
  811 + }
  812 +
  813 + /**
  814 + * This updates the metadata on the file. This includes the 'title'.
  815 + *
  816 + * @param array This is an array containing the metadata to be associated with the file.
  817 + */
  818 + function update_metadata($metadata)
  819 + {
  820 + $packed = array();
  821 +
  822 + foreach($metadata as $fieldset_metadata)
  823 + {
  824 + $fieldsetname=$fieldset_metadata['fieldset'];
  825 + $fieldset = KTFieldset::getByName($fieldsetname);
  826 + if (is_null($fieldset) || PEAR::isError($fieldset))
  827 + {
  828 + // exit graciously
  829 + continue;
  830 + }
  831 +
  832 + foreach($fieldset_metadata['fields'] as $fieldinfo)
  833 + {
  834 + $fieldname = $fieldinfo['name'];
  835 + $field = DocumentField::getByFieldsetAndName($fieldset, $fieldname);
  836 + if (is_null($field) || PEAR::isError($fieldset))
  837 + {
  838 + // exit graciously
  839 + continue;
  840 + }
  841 + $value = $fieldinfo['value'];
  842 +
  843 + $packed[] = array($field, $value);
  844 + }
  845 + }
  846 +
  847 + DBUtil::startTransaction();
  848 + $result = KTDocumentUtil::saveMetadata($this->document, $packed);
  849 +
  850 + if (is_null($result))
  851 + {
  852 + DBUtil::rollback();
  853 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR);
  854 + }
  855 + if (PEAR::isError($result))
  856 + {
  857 + DBUtil::rollback();
  858 + return new KTAPI_Error(sprintf(_kt("Unexpected validation failure: %s."), $result->getMessage()));
  859 + }
  860 + DBUtil::commit();
  861 + }
  862 +
  863 +
  864 + /**
  865 + * This returns a workflow transition
  866 + *
  867 + * @return array
  868 + */
  869 + function get_workflow_transitions()
  870 + {
  871 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW);
  872 +
  873 + if (PEAR::isError($user))
  874 + {
  875 + return $user;
  876 + }
  877 +
  878 + $workflowid=$this->document->getWorkflowId();
  879 + if (empty($workflowid))
  880 + {
  881 + return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS);
  882 + }
  883 +
  884 + $result = array();
  885 +
  886 + $transitions = KTWorkflowUtil::getTransitionsForDocumentUser($this->document, $user);
  887 + if (is_null($transitions) || PEAR::isError($transitions))
  888 + {
  889 + return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID, $transitions);
  890 + }
  891 + foreach($transitions as $transition)
  892 + {
  893 + $result[] = $transition->getName();
  894 + }
  895 +
  896 + return $result;
  897 + }
  898 +
  899 + /**
  900 + * This returns the current workflow state
  901 + *
  902 + * @return string
  903 + */
  904 + function get_workflow_state()
  905 + {
  906 + $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW);
  907 +
  908 + if (PEAR::isError($user))
  909 + {
  910 + return $user;
  911 + }
  912 +
  913 + $workflowid=$this->document->getWorkflowId();
  914 + if (empty($workflowid))
  915 + {
  916 + return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS);
  917 + }
  918 +
  919 + $result = array();
  920 +
  921 + $state = KTWorkflowUtil::getWorkflowStateForDocument($this->document);
  922 + if (is_null($state) || PEAR::isError($state))
  923 + {
  924 + return new PEAR_Error(KTAPI_ERROR_WORKFLOW_INVALID);
  925 + }
  926 +
  927 + $statename = $state->getName();
  928 +
  929 + return $statename;
  930 +
  931 + }
  932 +
  933 + /**
  934 + * This returns detailed information on the document.
  935 + *
  936 + * @return array
  937 + */
  938 + function get_detail()
  939 + {
  940 + $detail = array();
  941 + $document = $this->document;
  942 +
  943 + $detail['title'] = $document->getName();
  944 +
  945 + $documenttypeid=$document->getDocumentTypeID();
  946 + if (is_numeric($documenttypeid))
  947 + {
  948 + $documenttype = DocumentType::get($documenttypeid);
  949 +
  950 + $documenttype=$documenttype->getName();
  951 + }
  952 + else
  953 + {
  954 + $documenttype = '* unknown *';
  955 + }
  956 + $detail['document_type'] = $documenttype;
  957 +
  958 + $detail['version'] = $document->getVersion();
  959 + $detail['filename'] = $document->getFilename();
  960 +
  961 + $detail['created_date'] = $document->getCreatedDateTime();
  962 +
  963 + $userid = $document->getCreatorID();
  964 + if (is_numeric($userid))
  965 + {
  966 + $user = User::get($userid);
  967 + $username=(is_null($user) || PEAR::isError($user))?'* unknown *':$user->getName();
  968 + }
  969 + else
  970 + {
  971 + $username='n/a';
  972 + }
  973 + $detail['created_by'] = $username;
  974 + $detail['updated_date'] = $document->getLastModifiedDate();
  975 +
  976 + $userid = $document->getModifiedUserId();
  977 + if (is_numeric($userid))
  978 + {
  979 + $user = User::get($userid);
  980 + $username=(is_null($user) || PEAR::isError($user))?'* unknown *':$user->getName();
  981 + }
  982 + else
  983 + {
  984 + $username='n/a';
  985 + }
  986 + $detail['updated_by'] = $username;
  987 + $detail['document_id'] = (int) $document->getId();
  988 + $detail['folder_id'] = (int) $document->getFolderID();
  989 +
  990 + $workflowid = $document->getWorkflowId();
  991 + if (is_numeric($workflowid))
  992 + {
  993 + $workflow = KTWorkflow::get($workflowid);
  994 + $workflowname=(is_null($workflow) || PEAR::isError($workflow))?'* unknown *':$workflow->getName();
  995 + }
  996 + else
  997 + {
  998 + $workflowname='n/a';
  999 + }
  1000 + $detail['workflow'] = $workflowname;
  1001 +
  1002 + $stateid = $document->getWorkflowStateId();
  1003 + if (is_numeric($stateid))
  1004 + {
  1005 + $state = KTWorkflowState::get($stateid);
  1006 + $workflowstate=(is_null($state) || PEAR::isError($state))?'* unknown *':$state->getName();
  1007 + }
  1008 + else
  1009 + {
  1010 + $workflowstate = 'n/a';
  1011 + }
  1012 + $detail['workflow_state']=$workflowstate;
  1013 +
  1014 + $userid = $document->getCheckedOutUserID();
  1015 +
  1016 + if (is_numeric($userid))
  1017 + {
  1018 + $user = User::get($userid);
  1019 + $username=(is_null($user) || PEAR::isError($user))?'* unknown *':$user->getName();
  1020 + }
  1021 + else
  1022 + {
  1023 + $username = 'n/a';
  1024 + }
  1025 + $detail['checkout_by'] = $username;
  1026 +
  1027 + $detail['full_path'] = $this->ktapi_folder->get_full_path() . '/' . $this->get_title();
  1028 +
  1029 + return $detail;
  1030 + }
  1031 +
  1032 + function get_title()
  1033 + {
  1034 + return $this->document->getDescription();
  1035 + }
  1036 +
  1037 + /**
  1038 + * This does a download of a version of the document.
  1039 + *
  1040 + * @param string $version
  1041 + */
  1042 + function download($version=null)
  1043 + {
  1044 + $storage =& KTStorageManagerUtil::getSingleton();
  1045 + $options = array();
  1046 +
  1047 +
  1048 + $oDocumentTransaction = & new DocumentTransaction($this->document, 'Document downloaded', 'ktcore.transactions.download', $aOptions);
  1049 + $oDocumentTransaction->create();
  1050 + }
  1051 +
  1052 + /**
  1053 + * This returns the transaction history for the document.
  1054 + *
  1055 + * @return array
  1056 + */
  1057 + function get_transaction_history()
  1058 + {
  1059 + $sQuery = 'SELECT DTT.name AS transaction_name, U.name AS username, DT.version AS version, DT.comment AS comment, DT.datetime AS datetime ' .
  1060 + 'FROM ' . KTUtil::getTableName('document_transactions') . ' AS DT INNER JOIN ' . KTUtil::getTableName('users') . ' AS U ON DT.user_id = U.id ' .
  1061 + 'INNER JOIN ' . KTUtil::getTableName('transaction_types') . ' AS DTT ON DTT.namespace = DT.transaction_namespace ' .
  1062 + 'WHERE DT.document_id = ? ORDER BY DT.datetime DESC';
  1063 + $aParams = array($this->documentid);
  1064 +
  1065 + $transactions = DBUtil::getResultArray(array($sQuery, $aParams));
  1066 + if (is_null($transactions) || PEAR::isError($transactions))
  1067 + {
  1068 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $transactions );
  1069 + }
  1070 +
  1071 + return $transactions;
  1072 + }
  1073 +
  1074 + /**
  1075 + * This returns the version history on the document.
  1076 + *
  1077 + * @return array
  1078 + */
  1079 + function get_version_history()
  1080 + {
  1081 + $metadata_versions = KTDocumentMetadataVersion::getByDocument($this->document);
  1082 +
  1083 + $versions = array();
  1084 + foreach ($metadata_versions as $version)
  1085 + {
  1086 + $document = &Document::get($this->documentid, $version->getId());
  1087 +
  1088 + $version = array();
  1089 +
  1090 + $userid = $document->getModifiedUserId();
  1091 + $user = User::get($userid);
  1092 +
  1093 + $version['user'] = $user->getName();
  1094 + $version['metadata_version'] = $document->getMetadataVersion();
  1095 + $version['content_version'] = $document->getVersion();
  1096 +
  1097 + $versions[] = $version;
  1098 + }
  1099 + return $versions;
  1100 + }
  1101 +
  1102 + /**
  1103 + * This expunges a document from the system.
  1104 + *
  1105 + * @access public
  1106 + */
  1107 + function expunge()
  1108 + {
  1109 + if ($this->document->getStatusID() != 3)
  1110 + {
  1111 + return new PEAR_Error('You should not purge this');
  1112 + }
  1113 + DBUtil::startTransaction();
  1114 +
  1115 + $transaction = & new DocumentTransaction($this->document, "Document expunged", 'ktcore.transactions.expunge');
  1116 +
  1117 + $transaction->create();
  1118 +
  1119 + $this->document->delete();
  1120 +
  1121 + $this->document->cleanupDocumentData($this->documentid);
  1122 +
  1123 + $storage =& KTStorageManagerUtil::getSingleton();
  1124 +
  1125 + $result= $storage->expunge($this->document);
  1126 +
  1127 + DBUtil::commit();
  1128 + }
  1129 +
  1130 + /**
  1131 + * This expunges a document from the system.
  1132 + *
  1133 + * @access public
  1134 + */
  1135 + function restore()
  1136 + {
  1137 + DBUtil::startTransaction();
  1138 +
  1139 + $storage =& KTStorageManagerUtil::getSingleton();
  1140 +
  1141 + $folder = Folder::get($this->document->getRestoreFolderId());
  1142 + if (PEAR::isError($folder))
  1143 + {
  1144 + $this->document->setFolderId(1);
  1145 + $folder = Folder::get(1);
  1146 + }
  1147 + else
  1148 + {
  1149 + $this->document->setFolderId($this->document->getRestoreFolderId());
  1150 + }
  1151 +
  1152 + $storage->restore($this->document);
  1153 +
  1154 + $this->document->setStatusId(LIVE);
  1155 + $this->document->setPermissionObjectId($folder->getPermissionObjectId());
  1156 + $res = $this->document->update();
  1157 +
  1158 + $res = KTPermissionUtil::updatePermissionLookup($this->document);
  1159 +
  1160 + $user = $this->ktapi->get_user();
  1161 +
  1162 + $oTransaction = new DocumentTransaction($this->document, 'Restored from deleted state by ' . $user->getName(), 'ktcore.transactions.update');
  1163 + $oTransaction->create();
  1164 +
  1165 + DBUtil::commit();
  1166 + }
  1167 +}
  1168 +?>
0 \ No newline at end of file 1169 \ No newline at end of file
ktapi/KTAPIFolder.inc.php 0 → 100644
  1 +<?
  2 +
  3 +
  4 +class KTAPI_Folder extends KTAPI_FolderItem
  5 +{
  6 + /**
  7 + * This is a reference to a base Folder object.
  8 + *
  9 + * @access private
  10 + * @var Folder
  11 + */
  12 + var $folder;
  13 +
  14 + /**
  15 + * This is the id of the folder on the database.
  16 + *
  17 + * @access private
  18 + * @var int
  19 + */
  20 + var $folderid;
  21 +
  22 + /**
  23 + * This is used to get a folder based on a folder id.
  24 + *
  25 + * @access private
  26 + * @param KTAPI $ktapi
  27 + * @param int $folderid
  28 + * @return KTAPI_Folder
  29 + */
  30 + function &get(&$ktapi, $folderid)
  31 + {
  32 + assert(!is_null($ktapi));
  33 + assert(is_a($ktapi, 'KTAPI'));
  34 + assert(is_numeric($folderid));
  35 +
  36 + $folderid += 0;
  37 +
  38 + $folder = &Folder::get($folderid);
  39 + if (is_null($folder) || PEAR::isError($folder))
  40 + {
  41 + return new KTAPI_Error(KTAPI_ERROR_FOLDER_INVALID,$folder);
  42 + }
  43 +
  44 + $user = $ktapi->can_user_access_object_requiring_permission($folder, KTAPI_PERMISSION_READ);
  45 +
  46 + if (is_null($user) || PEAR::isError($user))
  47 + {
  48 + return $user;
  49 + }
  50 +
  51 + return new KTAPI_Folder($ktapi, $folder);
  52 + }
  53 +
  54 + /**
  55 + * This is the constructor for the KTAPI_Folder.
  56 + *
  57 + * @access private
  58 + * @param KTAPI $ktapi
  59 + * @param Folder $folder
  60 + * @return KTAPI_Folder
  61 + */
  62 + function KTAPI_Folder(&$ktapi, &$folder)
  63 + {
  64 + $this->ktapi = &$ktapi;
  65 + $this->folder = &$folder;
  66 + $this->folderid = $folder->getId();
  67 + }
  68 +
  69 + /**
  70 + * This returns a reference to the internal folder object.
  71 + *
  72 + * @access protected
  73 + * @return Folder
  74 + */
  75 + function &get_folder()
  76 + {
  77 + return $this->folder;
  78 + }
  79 +
  80 +
  81 + /**
  82 + * This returns detailed information on the document.
  83 + *
  84 + * @return array
  85 + */
  86 + function get_detail()
  87 + {
  88 + $detail = array(
  89 + 'id'=>(int) $this->folderid,
  90 + 'folder_name'=>$this->get_folder_name(),
  91 + 'parent_id'=>(int) $this->get_parent_folder_id(),
  92 + 'full_path'=>$this->get_full_path(),
  93 + );
  94 +
  95 + return $detail;
  96 + }
  97 +
  98 + function get_parent_folder_id()
  99 + {
  100 + return (int) $this->folder->getParentID();
  101 + }
  102 +
  103 + function get_folder_name()
  104 + {
  105 + return $this->folder->getFolderName($this->folderid);
  106 + }
  107 +
  108 +
  109 + /**
  110 + * This returns the folderid.
  111 + *
  112 + * @return int
  113 + */
  114 + function get_folderid()
  115 + {
  116 + return (int) $this->folderid;
  117 + }
  118 +
  119 + /**
  120 + * This can resolve a folder relative to the current directy by name
  121 + *
  122 + * @access public
  123 + * @param string $foldername
  124 + * @return KTAPI_Folder
  125 + */
  126 + function &get_folder_by_name($foldername)
  127 + {
  128 + $foldername=trim($foldername);
  129 + if (empty($foldername))
  130 + {
  131 + return new PEAR_Error('A valid folder name must be specified.');
  132 + }
  133 +
  134 + $split = explode('/', $foldername);
  135 +
  136 + $folderid=$this->folderid;
  137 + foreach($split as $foldername)
  138 + {
  139 + if (empty($foldername))
  140 + {
  141 + continue;
  142 + }
  143 + $sql = "SELECT id FROM folders WHERE name='$foldername' and parent_id=$folderid";
  144 + $row = DBUtil::getOneResult($sql);
  145 + if (is_null($row) || PEAR::isError($row))
  146 + {
  147 + return new KTAPI_Error(KTAPI_ERROR_FOLDER_INVALID,$row);
  148 + }
  149 + $folderid = $row['id'];
  150 + }
  151 +
  152 + return KTAPI_Folder::get($this->ktapi, $folderid);
  153 + }
  154 +
  155 + function get_full_path()
  156 + {
  157 + $path = $this->folder->getFullPath() . '/' . $this->folder->getName();
  158 +
  159 + return $path;
  160 + }
  161 +
  162 + /**
  163 + * This gets a document by filename or name.
  164 + *
  165 + * @access private
  166 + * @param string $documentname
  167 + * @param string $function
  168 + * @return KTAPI_Document
  169 + */
  170 + function &_get_document_by_name($documentname, $function='getByNameAndFolder')
  171 + {
  172 + $documentname=trim($documentname);
  173 + if (empty($documentname))
  174 + {
  175 + return new PEAR_Error('A valid document name must be specified.');
  176 + }
  177 +
  178 + $foldername = dirname($documentname);
  179 + $documentname = basename($documentname);
  180 +
  181 + $ktapi_folder = $this;
  182 +
  183 + if (!empty($foldername) && ($foldername != '.'))
  184 + {
  185 + $ktapi_folder = $this->get_folder_by_name($foldername);
  186 + }
  187 +
  188 + if (is_null($ktapi_folder) || PEAR::isError($ktapi_folder))
  189 + {
  190 + return new KTAPI_Error(KTAPI_ERROR_FOLDER_INVALID, $ktapi_folder);
  191 + }
  192 +
  193 + //$folder = $ktapi_folder->get_folder();
  194 + $folderid = $ktapi_folder->folderid;
  195 +
  196 + $document = Document::$function($documentname, $folderid);
  197 + if (is_null($document) || PEAR::isError($document))
  198 + {
  199 + return new KTAPI_Error(KTAPI_ERROR_DOCUMENT_INVALID, $document);
  200 + }
  201 +
  202 + $user = $this->can_user_access_object_requiring_permission($document, KTAPI_PERMISSION_READ);
  203 + if (PEAR::isError($user))
  204 + {
  205 + return $user;
  206 + }
  207 +
  208 + return new KTAPI_Document($this->ktapi, $ktapi_folder, $document);
  209 + }
  210 +
  211 + /**
  212 + * This can resolve a document relative to the current directy by name.
  213 + *
  214 + * @access public
  215 + * @param string $documentname
  216 + * @return KTAPI_Document
  217 + */
  218 + function &get_document_by_name($documentname)
  219 + {
  220 + return $this->_get_document_by_name($documentname,'getByNameAndFolder');
  221 + }
  222 +
  223 + /**
  224 + * This can resolve a document relative to the current directy by filename .
  225 + *
  226 + * @access public
  227 + * @param string $documentname
  228 + * @return KTAPI_Document
  229 + */
  230 + function &get_document_by_filename($documentname)
  231 + {
  232 + return $this->_get_document_by_name($documentname,'getByFilenameAndFolder');
  233 + }
  234 +
  235 + function get_listing($depth=1, $what='DF')
  236 + {
  237 + if ($depth < 1)
  238 + {
  239 + return array();
  240 + }
  241 + $permission = &KTPermission::getByName(KTAPI_PERMISSION_READ);
  242 + $permissionid= $permission->getId();
  243 +
  244 + $user = $this->ktapi->get_user();
  245 + $descriptors=KTPermissionUtil::getPermissionDescriptorsForUser($user);
  246 + if (is_null($descriptors) || PEAR::isError($descriptors))
  247 + {
  248 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR . ': problem with descriptors for user', $descriptors);
  249 + }
  250 + if (count($descriptors == 0))
  251 + {
  252 + $descriptors=array(0);
  253 + }
  254 +
  255 + $aPermissionDescriptors = implode(',',$descriptors);
  256 +
  257 + $sql = '';
  258 + if (strpos($what,'D') !== false)
  259 + {
  260 + $sql .= "SELECT
  261 + d.id,
  262 + 'D' as item_type,
  263 + dmv.name as title,
  264 + ifnull(uc.name, 'n/a') AS creator,
  265 + ifnull(cou.name, 'n/a') AS checkedoutby,
  266 + ifnull(mu.name, 'n/a') AS modifiedby,
  267 + dcv.filename,
  268 + dcv.size,
  269 + dcv.major_version,
  270 + dcv.minor_version,
  271 + dcv.storage_path,
  272 + ifnull(mt.mimetypes, 'unknown') as mime_type,
  273 + ifnull(mt.icon_path, 'unknown') as mime_icon_path,
  274 + ifnull(mt.friendly_name, 'unknown') as mime_display
  275 + FROM
  276 + documents d
  277 + INNER JOIN permission_lookups AS PL ON d.permission_lookup_id = PL.id
  278 + INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = $permissionid
  279 + INNER JOIN document_metadata_version AS dmv ON d.metadata_version_id=dmv.id
  280 + INNER JOIN document_content_version AS dcv ON dmv.content_version_id=dcv.id
  281 + LEFT OUTER JOIN mime_types mt ON dcv.mime_id = mt.id
  282 + LEFT OUTER JOIN users AS uc ON d.creator_id=uc.id
  283 + LEFT OUTER JOIN users AS cou ON d.checked_out_user_id=cou.id
  284 + LEFT OUTER JOIN users AS mu ON d.modified_user_id=mu.id
  285 + WHERE
  286 + d.folder_id=$this->folderid
  287 + AND d.status_id = 1
  288 + AND PLA.permission_descriptor_id IN ($aPermissionDescriptors)";
  289 + }
  290 +
  291 + if (strpos($what,'F') !== false)
  292 + {
  293 + if (strpos($what,'D') !== false)
  294 + {
  295 + $sql .= ' UNION ';
  296 + }
  297 +
  298 + $sql .= "
  299 + SELECT
  300 + f.id,
  301 + 'F' as item_type,
  302 + f.name as title,
  303 + ifnull(uc.name, 'n/a') AS creator,
  304 + 'n/a' checkedoutby,
  305 + 'n/a' AS modifiedby,
  306 + f.name as filename,
  307 + 'n/a' as size,
  308 + 'n/a' as major_version,
  309 + 'n/a' as minor_version,
  310 + 'n/a' as storage_path,
  311 + 'folder' as mime_type,
  312 + 'folder' as mime_icon_path,
  313 + 'Folder' as mime_display
  314 + FROM
  315 + folders f
  316 + INNER JOIN permission_lookups AS PL ON f.permission_lookup_id = PL.id
  317 + INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = $permissionid
  318 + LEFT OUTER JOIN users AS uc ON f.creator_id=uc.id
  319 +
  320 + WHERE
  321 + f.parent_id=$this->folderid
  322 +
  323 + AND PLA.permission_descriptor_id IN ($aPermissionDescriptors)
  324 + ORDER BY item_type DESC, title, filename
  325 + ";
  326 + }
  327 +
  328 + $contents = DBUtil::getResultArray($sql);
  329 + if (is_null($contents) || PEAR::isError($contents))
  330 + {
  331 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR , $contents);
  332 + }
  333 +
  334 + $num_items = count($contents);
  335 + for($i=0;$i<$num_items;$i++)
  336 + {
  337 + $contents[$i]['id'] = (int) $contents[$i]['id'];
  338 + if ($contents[$i]['item_type'] == 'D')
  339 + {
  340 + $contents[$i]['items'] = array();
  341 + }
  342 + else
  343 + {
  344 + if ($depth-1 > 0)
  345 + {
  346 + $folder = &$this->ktapi->get_folder_by_id($item['id']);
  347 + $contents[$i]['items'] = $folder->get_listing($depth-1);
  348 + }
  349 + else
  350 + {
  351 + $contents[$i]['items'] = array();
  352 + }
  353 + }
  354 + }
  355 +
  356 + return $contents;
  357 + }
  358 +
  359 + /**
  360 + * This adds a document to the current folder.
  361 + *
  362 + * @access public
  363 + * @param string $title This is the title for the file in the repository.
  364 + * @param string $filename This is the filename in the system for the file.
  365 + * @param string $documenttype This is the name or id of the document type. It first looks by name, then by id.
  366 + * @param string $tempfilename This is a reference to the file that is accessible locally on the file system.
  367 + * @return KTAPI_Document
  368 + */
  369 + function &add_document($title, $filename, $documenttype, $tempfilename)
  370 + {
  371 + if (!is_file($tempfilename))
  372 + {
  373 + return new PEAR_Error('File does not exist.');
  374 + }
  375 +
  376 + $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_WRITE);
  377 + if (PEAR::isError($user))
  378 + {
  379 + return $user;
  380 + }
  381 +
  382 + $filename = basename($filename);
  383 + $documenttypeid = KTAPI::get_documenttypeid($documenttype);
  384 +
  385 + $options = array(
  386 + 'contents' => new KTFSFileLike($tempfilename),
  387 + 'novalidate' => true,
  388 + 'documenttype' => DocumentType::get($documenttypeid),
  389 + 'description' => $title,
  390 + 'metadata'=>array(),
  391 + 'cleanup_initial_file' => true
  392 + );
  393 +
  394 + DBUtil::startTransaction();
  395 + $document =& KTDocumentUtil::add($this->folder, $filename, $user, $options);
  396 +
  397 + if (!is_a($document,'Document'))
  398 + {
  399 + DBUtil::rollback();
  400 + return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR . ' : ' . $document->getMessage());
  401 + }
  402 + DBUtil::commit();
  403 +
  404 + $tempfilename=addslashes($tempfilename);
  405 + $sql = "DELETE FROM uploaded_files WHERE tempfilename='$tempfilename'";
  406 + $result = DBUtil::runQuery($sql);
  407 + if (PEAR::isError($result))
  408 + {
  409 + return $result;
  410 + }
  411 +
  412 + return new KTAPI_Document($this->ktapi, $this, $document);
  413 + }
  414 +
  415 + /**
  416 + * This adds a subfolder folder to the current folder.
  417 + *
  418 + * @access public
  419 + * @param string $foldername
  420 + * @return KTAPI_Folder
  421 + */
  422 + function &add_folder($foldername)
  423 + {
  424 + $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_ADD_FOLDER);
  425 +
  426 + if (PEAR::isError($user))
  427 + {
  428 + return $user;
  429 + }
  430 +
  431 + DBUtil::startTransaction();
  432 + $result = KTFolderUtil::add($this->folder, $foldername, $user);
  433 +
  434 + if (PEAR::isError($result))
  435 + {
  436 + DBUtil::rollback();
  437 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $result);
  438 + }
  439 + DBUtil::commit();
  440 + $folderid = $result->getId();
  441 +
  442 + return $this->ktapi->get_folder_by_id($folderid);
  443 + }
  444 +
  445 + /**
  446 + * This deletes the current folder.
  447 + *
  448 + * @param string $reason
  449 + */
  450 + function delete($reason)
  451 + {
  452 + $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_DELETE);
  453 + if (PEAR::isError($user))
  454 + {
  455 + return $user;
  456 + }
  457 +
  458 + if ($this->folderid == 1)
  459 + {
  460 + return new PEAR_Error('Cannot delete root folder!');
  461 + }
  462 +
  463 + DBUtil::startTransaction();
  464 + $result = KTFolderUtil::delete($this->folder, $user, $reason);
  465 +
  466 + if (PEAR::isError($result))
  467 + {
  468 + DBUtil::rollback();
  469 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $result);
  470 + }
  471 + DBUtil::commit();
  472 + }
  473 +
  474 + /**
  475 + * This renames the folder
  476 + *
  477 + * @param string $newname
  478 + */
  479 + function rename($newname)
  480 + {
  481 + $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_RENAME_FOLDER);
  482 + if (PEAR::isError($user))
  483 + {
  484 + return $user;
  485 + }
  486 +
  487 + DBUtil::startTransaction();
  488 + $result = KTFolderUtil::rename($this->folder, $newname, $user);
  489 +
  490 + if (PEAR::isError($result))
  491 + {
  492 + DBUtil::rollback();
  493 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $result);
  494 + }
  495 + DBUtil::commit();
  496 + }
  497 +
  498 + /**
  499 + * This moves the folder to another location.
  500 + *
  501 + * @param KTAPI_Folder $ktapi_target_folder
  502 + * @param string $reason
  503 + */
  504 + function move($ktapi_target_folder, $reason='')
  505 + {
  506 + assert(!is_null($ktapi_target_folder));
  507 + assert(is_a($ktapi_target_folder,'KTAPI_Folder'));
  508 +
  509 + $user = $this->ktapi->get_user();
  510 +
  511 + $target_folder = $ktapi_target_folder->get_folder();
  512 +
  513 + $result = $this->can_user_access_object_requiring_permission($target_folder, KTAPI_PERMISSION_WRITE);
  514 + if (PEAR::isError($result))
  515 + {
  516 + return $result;
  517 + }
  518 +
  519 + DBUtil::startTransaction();
  520 + $result = KTFolderUtil::copy($this->folder, $target_folder, $user, $reason);
  521 +
  522 + if (PEAR::isError($result))
  523 + {
  524 + DBUtil::rollback();
  525 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $result);
  526 + }
  527 + DBUtil::commit();
  528 + }
  529 +
  530 + /**
  531 + * This copies a folder to another location.
  532 + *
  533 + * @param KTAPI_Folder $ktapi_target_folder
  534 + * @param string $reason
  535 + */
  536 + function copy($ktapi_target_folder, $reason='')
  537 + {
  538 + assert(!is_null($ktapi_target_folder));
  539 + assert(is_a($ktapi_target_folder,'KTAPI_Folder'));
  540 +
  541 + $user = $this->ktapi->get_user();
  542 +
  543 + $target_folder = $ktapi_target_folder->get_folder();
  544 +
  545 + $result =$this->can_user_access_object_requiring_permission($target_folder, KTAPI_PERMISSION_WRITE);
  546 +
  547 + if (PEAR::isError($result))
  548 + {
  549 + return $result;
  550 + }
  551 +
  552 + DBUtil::startTransaction();
  553 + $result = KTFolderUtil::copy($this->folder, $target_folder, $user, $reason);
  554 +
  555 + if (PEAR::isError($result))
  556 + {
  557 + DBUtil::rollback();
  558 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $result);
  559 + }
  560 + DBUtil::commit();
  561 + }
  562 +
  563 + /**
  564 + * This returns all permissions linked to the folder.
  565 + *
  566 + * @access public
  567 + * @return array
  568 + */
  569 + function get_permissions()
  570 + {
  571 + return new PEAR_Error('TODO');
  572 + }
  573 +
  574 + /**
  575 + * This returns a transaction history listing.
  576 + *
  577 + * @access public
  578 + * @return array
  579 + */
  580 + function get_transaction_history()
  581 + {
  582 + return new PEAR_Error('TODO');
  583 + }
  584 +}
  585 +
  586 +?>
0 \ No newline at end of file 587 \ No newline at end of file
ktapi/KTAPISession.inc.php 0 → 100644
  1 +<?
  2 +
  3 +class KTAPI_Session
  4 +{
  5 + var $ktapi;
  6 + var $user = null;
  7 + var $session = '';
  8 + var $sessionid = -1;
  9 + var $active;
  10 +
  11 + function KTAPI_Session(&$ktapi, &$user)
  12 + {
  13 + assert(!is_null($ktapi));
  14 + assert(is_a($ktapi,'KTAPI'));
  15 + assert(!is_null($user));
  16 + assert(is_a($user,'User'));
  17 +
  18 + $this->ktapi=&$ktapi;
  19 + $this->user=&$user;
  20 + $this->active = false;
  21 + }
  22 +
  23 + /**
  24 + * return the session string
  25 + *
  26 + * @return string
  27 + */
  28 + function get_session()
  29 + {
  30 + die('get_session() should be overloaded!');
  31 + }
  32 +
  33 + /**
  34 + * Return the session id
  35 + *
  36 + * @return int
  37 + */
  38 + function get_sessionid()
  39 + {
  40 + die('get_sessionid() should be overloaded!');
  41 + }
  42 +
  43 + /**
  44 + * Return the user
  45 + *
  46 + * @return User
  47 + */
  48 + function &get_user()
  49 + {
  50 + return $this->user;
  51 + }
  52 +
  53 + function logout()
  54 + {
  55 + $this->active=false;
  56 + // don't need to do anything really
  57 + }
  58 +
  59 + function is_active()
  60 + {
  61 + return $this->active;
  62 + }
  63 +
  64 +}
  65 +
  66 +
  67 +class KTAPI_UserSession extends KTAPI_Session
  68 +{
  69 + var $ip = null;
  70 +
  71 + function KTAPI_UserSession(&$ktapi, &$user, $session, $sessionid, $ip)
  72 + {
  73 + parent::KTAPI_Session($ktapi, $user);
  74 +
  75 + $this->ktapi = &$ktapi;
  76 + $this->user = &$user;
  77 + $this->session = $session;
  78 + $this->sessionid = $sessionid;
  79 + $this->ip = $ip;
  80 +
  81 + // TODO: get documenttransaction to not look at the session variable!
  82 + $_SESSION["userID"] = $user->getId();
  83 + $_SESSION["sessionID"] = $this->sessionid;
  84 + $this->active = true;
  85 + }
  86 +
  87 + /**
  88 + * This returns the session string
  89 + *
  90 + * @return string
  91 + */
  92 + function get_session()
  93 + {
  94 + return $this->session;
  95 + }
  96 +
  97 + /**
  98 + * This returns the sessionid in the database.
  99 + *
  100 + * @return int
  101 + */
  102 + function get_sessionid()
  103 + {
  104 + return $this->sessionid;
  105 + }
  106 +
  107 + /**
  108 + * This resolves the user's ip
  109 + *
  110 + * @access private
  111 + * @return string
  112 + */
  113 + function resolveIP()
  114 + {
  115 + if (getenv("REMOTE_ADDR"))
  116 + {
  117 + $ip = getenv("REMOTE_ADDR");
  118 + }
  119 + elseif (getenv("HTTP_X_FORWARDED_FOR"))
  120 + {
  121 + $forwardedip = getenv("HTTP_X_FORWARDED_FOR");
  122 + list($ip,$ip2,$ip3,$ip4)= split (",", $forwardedip);
  123 + }
  124 + elseif (getenv("HTTP_CLIENT_IP"))
  125 + {
  126 + $ip = getenv("HTTP_CLIENT_IP");
  127 + }
  128 +
  129 + if ($ip == '')
  130 + {
  131 + $ip = '127.0.0.1';
  132 + }
  133 +
  134 + return $ip;
  135 + }
  136 +
  137 + /**
  138 + *
  139 + * @access protected
  140 + * @static
  141 + * @param User $user
  142 + */
  143 + function _check_session(&$user)
  144 + {
  145 + $user_id = $user->getId();
  146 +
  147 + $sql = "SELECT count(*) >= u.max_sessions as over_limit FROM active_sessions ass INNER JOIN users u ON ass.user_id=u.id WHERE ass.user_id = $user_id";
  148 + $row = DBUtil::getOneResult($sql);
  149 + if (PEAR::isError($row))
  150 + {
  151 + return $row;
  152 + }
  153 + if (is_null($row))
  154 + {
  155 + return new PEAR_Error('No record found for user?');
  156 + }
  157 + if ($row['over_limit'] == 1)
  158 + {
  159 + return new PEAR_Error('Session limit exceeded. Logout of any active sessions.');
  160 + }
  161 +
  162 + $session = session_id();
  163 +
  164 + $sessionid = DBUtil::autoInsert('active_sessions',
  165 + array(
  166 + 'user_id' => $user_id,
  167 + 'session_id' => session_id(),
  168 + 'lastused' => date('Y-m-d H:i:s'),
  169 + 'ip' => $ip
  170 + ));
  171 + if (PEAR::isError($sessionid) )
  172 + {
  173 + return $sessionid;
  174 + }
  175 +
  176 + return array($session,$sessionid);
  177 + }
  178 +
  179 +
  180 + /**
  181 + * This returns a session object based on authentication credentials.
  182 + *
  183 + * @access public
  184 + * @static
  185 + * @param string $username
  186 + * @param string $password
  187 + * @return KTAPI_Session
  188 + */
  189 + function &start_session(&$ktapi, $username, $password, $ip=null)
  190 + {
  191 + $this->active=false;
  192 + if ( empty($username) )
  193 + {
  194 + return new PEAR_Error(_kt('The username is empty.'));
  195 + }
  196 +
  197 + $user =& User::getByUsername($username);
  198 + if (PEAR::isError($user) || ($user === false))
  199 + {
  200 + return new KTAPI_Error(_kt("The user '$username' cound not be found."),$user);
  201 + }
  202 +
  203 + if ( empty($password) )
  204 + {
  205 + return new PEAR_Error(_kt('The password is empty.'));
  206 + }
  207 +
  208 + $authenticated = KTAuthenticationUtil::checkPassword($user, $password);
  209 +
  210 + if (PEAR::isError($authenticated) || $authenticated === false)
  211 + {
  212 + return new KTAPI_Error(_kt("The password is invalid."),$authenticated);
  213 + }
  214 +
  215 + if (is_null($ip))
  216 + {
  217 + $ip = '127.0.0.1';
  218 + //$ip = KTAPI_Session::resolveIP();
  219 + }
  220 +
  221 + list($session,$sessionid) = KTAPI_UserSession::_check_session($user);
  222 + if (PEAR::isError($sessionid))
  223 + {
  224 + return $sessionid;
  225 + }
  226 +
  227 + $session = &new KTAPI_UserSession($ktapi, $user, $session, $sessionid, $ip);
  228 +
  229 + return $session;
  230 + }
  231 +
  232 + /**
  233 + * This returns an active session.
  234 + *
  235 + * @param KTAPI $ktapi
  236 + * @param string $session
  237 + * @param string $ip
  238 + * @return KTAPI_Session
  239 + */
  240 + function &get_active_session(&$ktapi, $session, $ip)
  241 + {
  242 + $sql = "SELECT id, user_id FROM active_sessions WHERE session_id='$session'";
  243 + if (!empty($ip))
  244 + {
  245 + $sql .= " AND ip='$ip'";
  246 + }
  247 +
  248 + $row = DBUtil::getOneResult($sql);
  249 + if (is_null($row) || PEAR::isError($row))
  250 + {
  251 + return new KTAPI_Error(KTAPI_ERROR_SESSION_INVALID, $row);
  252 + }
  253 +
  254 + $sessionid = $row['id'];
  255 + $userid = $row['user_id'];
  256 +
  257 + $user = &User::get($userid);
  258 + if (is_null($user) || PEAR::isError($user))
  259 + {
  260 + return new KTAPI_Error(KTAPI_ERROR_USER_INVALID, $user);
  261 + }
  262 +
  263 +
  264 +
  265 + $now=date('Y-m-d H:i:s');
  266 + $sql = "UPDATE active_sessions SET last_used='$now' WHERE id=$sessionid";
  267 + DBUtil::runQuery($sql);
  268 +
  269 + $session = &new KTAPI_UserSession($ktapi, $user, $session, $sessionid, $ip);
  270 + return $session;
  271 + }
  272 +
  273 + /**
  274 + * This closes the current session.
  275 + *
  276 + */
  277 + function logout()
  278 + {
  279 + $sql = "DELETE FROM active_sessions WHERE id=$this->sessionid";
  280 + $result = DBUtil::runQuery($sql);
  281 + if (PEAR::isError($result))
  282 + {
  283 + return $result;
  284 + }
  285 +
  286 + $this->user = null;
  287 + $this->session = '';
  288 + $this->sessionid = -1;
  289 + $this->active=false;
  290 + }
  291 +
  292 +}
  293 +
  294 +class KTAPI_AnonymousSession extends KTAPI_UserSession
  295 +{
  296 + function &start_session(&$ktapi, $ip=null)
  297 + {
  298 + $user =& User::get(-2);
  299 + if (is_null($user) || PEAR::isError($user) || ($user === false) || !$user->isAnonymous())
  300 + {
  301 + return new KTAPI_Error(_kt("The anonymous user could not be found."), $user);
  302 + }
  303 +
  304 + $authenticated = true;
  305 +
  306 + $config = &KTConfig::getSingleton();
  307 + $allow_anonymous = $config->get('session/allowAnonymousLogin', false);
  308 +
  309 + if (!$allow_anonymous)
  310 + {
  311 + return new PEAR_Error(_kt('Anonymous user not allowed'));
  312 + }
  313 +
  314 + if (is_null($ip))
  315 + {
  316 + $ip = '127.0.0.1';
  317 + //$ip = KTAPI_Session::resolveIP();
  318 + }
  319 +
  320 + list($session,$sessionid) = KTAPI_UserSession::_check_session($user);
  321 + if (PEAR::isError($sessionid))
  322 + {
  323 + return $sessionid;
  324 + }
  325 +
  326 + $session = &new KTAPI_AnonymousSession($ktapi, $user, $session, $sessionid, $ip);
  327 +
  328 + return $session;
  329 + }
  330 +}
  331 +
  332 +
  333 +
  334 +class KTAPI_SystemSession extends KTAPI_Session
  335 +{
  336 + function KTAPI_SystemSession(&$ktapi, &$user)
  337 + {
  338 + parent::KTAPI_Session($ktapi, $user);
  339 + $this->active=true;
  340 + }
  341 +}
  342 +
  343 +?>
0 \ No newline at end of file 344 \ No newline at end of file
ktapi/ktapi.inc.php
@@ -30,2026 +30,44 @@ @@ -30,2026 +30,44 @@
30 * 30 *
31 */ 31 */
32 32
  33 +session_start();
33 require_once('../config/dmsDefaults.php'); 34 require_once('../config/dmsDefaults.php');
34 require_once(KT_LIB_DIR . '/filelike/fsfilelike.inc.php'); 35 require_once(KT_LIB_DIR . '/filelike/fsfilelike.inc.php');
35 require_once(KT_LIB_DIR . '/foldermanagement/folderutil.inc.php'); 36 require_once(KT_LIB_DIR . '/foldermanagement/folderutil.inc.php');
36 37
37 -// Generic error messages used in the API. There may be some others specific to functionality  
38 -// directly in the code.  
39 -// TODO: Check that they are all relevant.  
40 -  
41 -define('KTAPI_ERROR_SESSION_INVALID', 'The session could not be resolved.');  
42 -define('KTAPI_ERROR_PERMISSION_INVALID', 'The permission could not be resolved.');  
43 -define('KTAPI_ERROR_FOLDER_INVALID', 'The folder could not be resolved.');  
44 -define('KTAPI_ERROR_DOCUMENT_INVALID', 'The document could not be resolved.');  
45 -define('KTAPI_ERROR_USER_INVALID', 'The user could not be resolved.');  
46 -define('KTAPI_ERROR_KTAPI_INVALID', 'The ktapi could not be resolved.');  
47 -define('KTAPI_ERROR_INSUFFICIENT_PERMISSIONS', 'The user does not have sufficient permissions to access the resource.');  
48 -define('KTAPI_ERROR_INTERNAL_ERROR', 'An internal error occurred. Please review the logs.');  
49 -define('KTAPI_ERROR_DOCUMENT_TYPE_INVALID', 'The document type could not be resolved.');  
50 -define('KTAPI_ERROR_DOCUMENT_CHECKED_OUT', 'The document is checked out.');  
51 -define('KTAPI_ERROR_DOCUMENT_NOT_CHECKED_OUT', 'The document is not checked out.');  
52 -define('KTAPI_ERROR_WORKFLOW_INVALID', 'The workflow could not be resolved.');  
53 -define('KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS', 'The workflow is not in progress.');  
54 -  
55 -// Mapping of permissions to actions.  
56 -// TODO: Check that they are all correct.  
57 -// Note, currently, all core actions have permissions that are defined in the plugins.  
58 -// As the permissions are currently associated with actions which are quite closely linked  
59 -// to the web interface, it is not the nicest way to do things. They should be associated at  
60 -// a lower level, such as in the api. probably, better, would be at some stage to assocate  
61 -// the permissions to the action/transaction in the database so administrators can really customise  
62 -// as required.  
63 -  
64 -define('KTAPI_PERMISSION_DELETE', 'ktcore.permissions.delete');  
65 -define('KTAPI_PERMISSION_READ', 'ktcore.permissions.read');  
66 -define('KTAPI_PERMISSION_WRITE', 'ktcore.permissions.write');  
67 -define('KTAPI_PERMISSION_ADD_FOLDER', 'ktcore.permissions.addFolder');  
68 -define('KTAPI_PERMISSION_RENAME_FOLDER', 'ktcore.permissions.folder_rename');  
69 -define('KTAPI_PERMISSION_CHANGE_OWNERSHIP', 'ktcore.permissions.security');  
70 -define('KTAPI_PERMISSION_DOCUMENT_MOVE', 'ktcore.permissions.write');  
71 -define('KTAPI_PERMISSION_WORKFLOW', 'ktcore.permissions.workflow');  
72 -  
73 -//  
74 -  
75 -class KTAPI_Session  
76 -{  
77 - var $ktapi;  
78 - var $user = null;  
79 - var $session = '';  
80 - var $sessionid = -1;  
81 - var $ip = null;  
82 -  
83 - function KTAPI_Session(&$ktapi, &$user, $session, $sessionid, $ip)  
84 - {  
85 - assert(!is_null($ktapi));  
86 - assert(is_a($ktapi,'KTAPI'));  
87 - assert(!is_null($user));  
88 - assert(is_a($user,'User'));  
89 -  
90 - $this->ktapi = &$ktapi;  
91 - $this->user = &$user;  
92 - $this->session = $session;  
93 - $this->sessionid = $sessionid;  
94 - $this->ip = $ip;  
95 -  
96 - // TODO: get documenttransaction to not look at the session variable!  
97 - $_SESSION["userID"] = $user->getId();  
98 - $_SESSION["sessionID"] = $this->sessionid;  
99 - }  
100 -  
101 - /**  
102 - * This returns the session string  
103 - *  
104 - * @return string  
105 - */  
106 - function get_session()  
107 - {  
108 - return $this->session;  
109 - }  
110 -  
111 - /**  
112 - * This returns the sessionid in the database.  
113 - *  
114 - * @return int  
115 - */  
116 - function get_sessionid()  
117 - {  
118 - return $this->sessionid;  
119 - }  
120 -  
121 - /**  
122 - * This returns a user object for the use rassociated with the session.  
123 - *  
124 - * @return User  
125 - */  
126 - function &get_user()  
127 - {  
128 - return $this->user;  
129 - }  
130 -  
131 - /**  
132 - * This resolves the user's ip  
133 - *  
134 - * @access private  
135 - * @return string  
136 - */  
137 - function resolveIP()  
138 - {  
139 - if (getenv("REMOTE_ADDR"))  
140 - {  
141 - $ip = getenv("REMOTE_ADDR");  
142 - }  
143 - elseif (getenv("HTTP_X_FORWARDED_FOR"))  
144 - {  
145 - $forwardedip = getenv("HTTP_X_FORWARDED_FOR");  
146 - list($ip,$ip2,$ip3,$ip4)= split (",", $forwardedip);  
147 - }  
148 - elseif (getenv("HTTP_CLIENT_IP"))  
149 - {  
150 - $ip = getenv("HTTP_CLIENT_IP");  
151 - }  
152 -  
153 - if ($ip == '')  
154 - {  
155 - $ip = '127.0.0.1';  
156 - }  
157 -  
158 - return $ip;  
159 - }  
160 -  
161 - /**  
162 - * This returns a session object based on authentication credentials.  
163 - *  
164 - * @access private  
165 - * @param string $username  
166 - * @param string $password  
167 - * @return KTAPI_Session  
168 - */  
169 - function &start_session(&$ktapi, $username, $password, $ip=null)  
170 - {  
171 -  
172 - if ( empty($username) )  
173 - {  
174 - return new PEAR_Error(_kt('The username is empty.'));  
175 - }  
176 -  
177 - $user =& User::getByUsername($username);  
178 - if (PEAR::isError($user) || ($user === false))  
179 - {  
180 - return new PEAR_Error(_kt("The user '$username' cound not be found."));  
181 - }  
182 -  
183 - if ($user->isAnonymous())  
184 - {  
185 - $authenticated = true;  
186 -  
187 - $config = &KTConfig::getSingleton();  
188 - $allow_anonymous = $config->get('session/allowAnonymousLogin', false);  
189 -  
190 - if (!$allow_anonymous)  
191 - {  
192 - return new PEAR_Error(_kt('Anonymous user not allowed'));  
193 - }  
194 -  
195 - }  
196 - else  
197 - {  
198 -  
199 - if ( empty($password) )  
200 - {  
201 - return new PEAR_Error(_kt('The password is empty.'));  
202 - }  
203 -  
204 - $authenticated = KTAuthenticationUtil::checkPassword($user, $password);  
205 -  
206 - if (PEAR::isError($authenticated) || $authenticated === false)  
207 - {  
208 - return new PEAR_Error(_kt("The password is invalid."));  
209 - }  
210 - }  
211 -  
212 -  
213 -  
214 -  
215 - if (is_null($ip))  
216 - {  
217 - $ip = '127.0.0.1';  
218 - //$ip = KTAPI_Session::resolveIP();  
219 - }  
220 -  
221 - session_start();  
222 -  
223 - $user_id = $user->getId();  
224 -  
225 - $sql = "SELECT count(*) >= u.max_sessions as over_limit FROM active_sessions ass INNER JOIN users u ON ass.user_id=u.id WHERE ass.user_id = $user_id";  
226 - $row = DBUtil::getOneResult($sql);  
227 - if (PEAR::isError($row))  
228 - {  
229 - return $row;  
230 - }  
231 - if (is_null($row))  
232 - {  
233 - return new PEAR_Error('No record found for user?');  
234 - }  
235 - if ($row['over_limit'] == 1)  
236 - {  
237 - return new PEAR_Error('Session limit exceeded. Logout of any active sessions.');  
238 - }  
239 -  
240 - $session = session_id();  
241 -  
242 - $sessionid = DBUtil::autoInsert('active_sessions',  
243 - array(  
244 - 'user_id' => $user_id,  
245 - 'session_id' => session_id(),  
246 - 'lastused' => date('Y-m-d H:i:s'),  
247 - 'ip' => $ip  
248 - ));  
249 - if (PEAR::isError($sessionid) )  
250 - {  
251 - return $sessionid;  
252 - }  
253 -  
254 - $session = &new KTAPI_Session($ktapi, $user, $session, $sessionid, $ip);  
255 -  
256 - return $session;  
257 - }  
258 -  
259 - /**  
260 - * This returns an active session.  
261 - *  
262 - * @param KTAPI $ktapi  
263 - * @param string $session  
264 - * @param string $ip  
265 - * @return KTAPI_Session  
266 - */  
267 - function &get_active_session(&$ktapi, $session, $ip)  
268 - {  
269 - $sql = "SELECT id, user_id FROM active_sessions WHERE session_id='$session'";  
270 - if (!empty($ip))  
271 - {  
272 - $sql .= " AND ip='$ip'";  
273 - }  
274 -  
275 - $row = DBUtil::getOneResult($sql);  
276 - if (is_null($row) || PEAR::isError($row))  
277 - {  
278 - return new PEAR_Error(KTAPI_ERROR_SESSION_INVALID);  
279 - }  
280 -  
281 - $sessionid = $row['id'];  
282 - $userid = $row['user_id'];  
283 -  
284 - $user = &User::get($userid);  
285 - if (is_null($user) || PEAR::isError($user))  
286 - {  
287 - return new PEAR_Error(KTAPI_ERROR_USER_INVALID);  
288 - }  
289 -  
290 -  
291 -  
292 - $now=date('Y-m-d H:i:s');  
293 - $sql = "UPDATE active_sessions SET last_used='$now' WHERE id=$sessionid";  
294 - DBUtil::runQuery($sql);  
295 -  
296 - $session = &new KTAPI_Session($ktapi, $user, $session, $sessionid, $ip);  
297 - return $session;  
298 - }  
299 -  
300 - /**  
301 - * This closes the current session.  
302 - *  
303 - */  
304 - function logout()  
305 - {  
306 - $sql = "DELETE FROM active_sessions WHERE id=$this->sessionid";  
307 - $result = DBUtil::runQuery($sql);  
308 - if (PEAR::isError($result))  
309 - {  
310 - return $result;  
311 - }  
312 -  
313 - $this->user = null;  
314 - $this->session = '';  
315 - $this->sessionid = -1;  
316 - }  
317 -  
318 -}  
319 -  
320 -class KTAPI_FolderItem  
321 -{  
322 - /**  
323 - * This is a reference to the core KTAPI controller  
324 - *  
325 - * @access protected  
326 - * @var KTAPI  
327 - */  
328 - var $ktapi;  
329 -  
330 - function &can_user_access_object_requiring_permission(&$object, $permission)  
331 - {  
332 - return $this->ktapi->can_user_access_object_requiring_permission($object, $permission);  
333 - }  
334 -}  
335 -  
336 -  
337 -class KTAPI_Folder extends KTAPI_FolderItem  
338 -{  
339 - /**  
340 - * This is a reference to a base Folder object.  
341 - *  
342 - * @access private  
343 - * @var Folder  
344 - */  
345 - var $folder;  
346 -  
347 - /**  
348 - * This is the id of the folder on the database.  
349 - *  
350 - * @access private  
351 - * @var int  
352 - */  
353 - var $folderid;  
354 -  
355 - /**  
356 - * This is used to get a folder based on a folder id.  
357 - *  
358 - * @access private  
359 - * @param KTAPI $ktapi  
360 - * @param int $folderid  
361 - * @return KTAPI_Folder  
362 - */  
363 - function &get(&$ktapi, $folderid)  
364 - {  
365 - assert(!is_null($ktapi));  
366 - assert(is_a($ktapi, 'KTAPI'));  
367 - assert(is_numeric($folderid));  
368 -  
369 - $folderid += 0;  
370 -  
371 - $folder = &Folder::get($folderid);  
372 - if (is_null($folder) || PEAR::isError($folder))  
373 - {  
374 - return new PEAR_Error(KTAPI_ERROR_FOLDER_INVALID);  
375 - }  
376 -  
377 - $user = $ktapi->can_user_access_object_requiring_permission($folder, KTAPI_PERMISSION_READ);  
378 -  
379 - if (is_null($user) || PEAR::isError($user))  
380 - {  
381 - return $user;  
382 - }  
383 -  
384 - return new KTAPI_Folder($ktapi, $folder);  
385 - }  
386 -  
387 - /**  
388 - * This is the constructor for the KTAPI_Folder.  
389 - *  
390 - * @access private  
391 - * @param KTAPI $ktapi  
392 - * @param Folder $folder  
393 - * @return KTAPI_Folder  
394 - */  
395 - function KTAPI_Folder(&$ktapi, &$folder)  
396 - {  
397 - $this->ktapi = &$ktapi;  
398 - $this->folder = &$folder;  
399 - $this->folderid = $folder->getId();  
400 - }  
401 -  
402 - /**  
403 - * This returns a reference to the internal folder object.  
404 - *  
405 - * @access protected  
406 - * @return Folder  
407 - */  
408 - function &get_folder()  
409 - {  
410 - return $this->folder;  
411 - }  
412 -  
413 -  
414 - /**  
415 - * This returns detailed information on the document.  
416 - *  
417 - * @return array  
418 - */  
419 - function get_detail()  
420 - {  
421 - $detail = array(  
422 - 'id'=>(int) $this->folderid,  
423 - 'folder_name'=>$this->get_folder_name(),  
424 - 'parent_id'=>(int) $this->get_parent_folder_id(),  
425 - 'full_path'=>$this->get_full_path(),  
426 - );  
427 -  
428 - return $detail;  
429 - }  
430 -  
431 - function get_parent_folder_id()  
432 - {  
433 - return (int) $this->folder->getParentID();  
434 - }  
435 -  
436 - function get_folder_name()  
437 - {  
438 - return $this->folder->getFolderName($this->folderid);  
439 - }  
440 -  
441 -  
442 - /**  
443 - * This returns the folderid.  
444 - *  
445 - * @return int  
446 - */  
447 - function get_folderid()  
448 - {  
449 - return (int) $this->folderid;  
450 - }  
451 -  
452 - /**  
453 - * This can resolve a folder relative to the current directy by name  
454 - *  
455 - * @access public  
456 - * @param string $foldername  
457 - * @return KTAPI_Folder  
458 - */  
459 - function &get_folder_by_name($foldername)  
460 - {  
461 - $foldername=trim($foldername);  
462 - if (empty($foldername))  
463 - {  
464 - return new PEAR_Error('A valid folder name must be specified.');  
465 - }  
466 -  
467 - $split = explode('/', $foldername);  
468 -  
469 - $folderid=$this->folderid;  
470 - foreach($split as $foldername)  
471 - {  
472 - $sql = "SELECT id FROM folders WHERE name='$foldername' and parent_id=$folderid";  
473 - $row = DBUtil::getOneResult($sql);  
474 - if (is_null($row) || PEAR::isError($row))  
475 - {  
476 - return new PEAR_Error(KTAPI_ERROR_FOLDER_INVALID);  
477 - }  
478 - $folderid = $row['id'];  
479 - }  
480 -  
481 - return KTAPI_Folder::get($this->ktapi, $folderid);  
482 - }  
483 -  
484 - function get_full_path()  
485 - {  
486 - $path = $this->folder->getFullPath() . '/' . $this->folder->getName();  
487 -  
488 - return $path;  
489 - }  
490 -  
491 - /**  
492 - * This gets a document by filename or name.  
493 - *  
494 - * @access private  
495 - * @param string $documentname  
496 - * @param string $function  
497 - * @return KTAPI_Document  
498 - */  
499 - function &_get_document_by_name($documentname, $function='getByNameAndFolder')  
500 - {  
501 - $documentname=trim($documentname);  
502 - if (empty($documentname))  
503 - {  
504 - return new PEAR_Error('A valid document name must be specified.');  
505 - }  
506 -  
507 - $foldername = dirname($documentname);  
508 - $documentname = basename($documentname);  
509 -  
510 - $ktapi_folder = $this;  
511 -  
512 - if (!empty($foldername) && ($foldername != '.'))  
513 - {  
514 - $ktapi_folder = $this->get_folder_by_name($foldername);  
515 - }  
516 -  
517 - if (is_null($ktapi_folder) || PEAR::isError($ktapi_folder))  
518 - {  
519 - return new PEAR_Error(KTAPI_ERROR_FOLDER_INVALID);  
520 - }  
521 -  
522 - //$folder = $ktapi_folder->get_folder();  
523 - $folderid = $ktapi_folder->folderid;  
524 -  
525 - $document = Document::$function($documentname, $folderid);  
526 - if (is_null($document) || PEAR::isError($document))  
527 - {  
528 - return new PEAR_Error(KTAPI_ERROR_DOCUMENT_INVALID);  
529 - }  
530 -  
531 - $user = $this->can_user_access_object_requiring_permission($document, KTAPI_PERMISSION_READ);  
532 - if (PEAR::isError($user))  
533 - {  
534 - return $user;  
535 - }  
536 -  
537 - return new KTAPI_Document($this->ktapi, $ktapi_folder, $document);  
538 - }  
539 -  
540 - /**  
541 - * This can resolve a document relative to the current directy by name.  
542 - *  
543 - * @access public  
544 - * @param string $documentname  
545 - * @return KTAPI_Document  
546 - */  
547 - function &get_document_by_name($documentname)  
548 - {  
549 - return $this->_get_document_by_name($documentname,'getByNameAndFolder');  
550 - }  
551 -  
552 - /**  
553 - * This can resolve a document relative to the current directy by filename .  
554 - *  
555 - * @access public  
556 - * @param string $documentname  
557 - * @return KTAPI_Document  
558 - */  
559 - function &get_document_by_filename($documentname)  
560 - {  
561 - return $this->_get_document_by_name($documentname,'getByFilenameAndFolder');  
562 - }  
563 -  
564 - function get_listing($depth=1, $what='DF')  
565 - {  
566 - if ($depth < 1)  
567 - {  
568 - return array();  
569 - }  
570 - $permission = &KTPermission::getByName(KTAPI_PERMISSION_READ);  
571 - $permissionid= $permission->getId();  
572 -  
573 - $user = $this->ktapi->get_user();  
574 - $aPermissionDescriptors = implode(',',KTPermissionUtil::getPermissionDescriptorsForUser($user));  
575 -  
576 - $sql = '';  
577 - if (strpos($what,'D') !== false)  
578 - {  
579 - $sql .= "SELECT  
580 - d.id,  
581 - 'D' as item_type,  
582 - dmv.name as title,  
583 - ifnull(uc.name, 'n/a') AS creator,  
584 - ifnull(cou.name, 'n/a') AS checkedoutby,  
585 - ifnull(mu.name, 'n/a') AS modifiedby,  
586 - dcv.filename,  
587 - dcv.size,  
588 - dcv.major_version,  
589 - dcv.minor_version,  
590 - dcv.storage_path,  
591 - ifnull(mt.mimetypes, 'unknown') as mime_type,  
592 - ifnull(mt.icon_path, 'unknown') as mime_icon_path,  
593 - ifnull(mt.friendly_name, 'unknown') as mime_display  
594 - FROM  
595 - documents d  
596 - INNER JOIN permission_lookups AS PL ON d.permission_lookup_id = PL.id  
597 - INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = $permissionid  
598 - INNER JOIN document_metadata_version AS dmv ON d.metadata_version_id=dmv.id  
599 - INNER JOIN document_content_version AS dcv ON dmv.content_version_id=dcv.id  
600 - LEFT OUTER JOIN mime_types mt ON dcv.mime_id = mt.id  
601 - LEFT OUTER JOIN users AS uc ON d.creator_id=uc.id  
602 - LEFT OUTER JOIN users AS cou ON d.checked_out_user_id=cou.id  
603 - LEFT OUTER JOIN users AS mu ON d.modified_user_id=mu.id  
604 - WHERE  
605 - d.folder_id=$this->folderid  
606 - AND d.status_id = 1  
607 - AND PLA.permission_descriptor_id IN ($aPermissionDescriptors)";  
608 - }  
609 -  
610 - if (strpos($what,'F') !== false)  
611 - {  
612 - if (strpos($what,'D') !== false)  
613 - {  
614 - $sql .= ' UNION ';  
615 - }  
616 -  
617 - $sql .= "  
618 - SELECT  
619 - f.id,  
620 - 'F' as item_type,  
621 - f.name as title,  
622 - ifnull(uc.name, 'n/a') AS creator,  
623 - 'n/a' checkedoutby,  
624 - 'n/a' AS modifiedby,  
625 - f.name as filename,  
626 - 'n/a' as size,  
627 - 'n/a' as major_version,  
628 - 'n/a' as minor_version,  
629 - 'n/a' as storage_path,  
630 - 'folder' as mime_type,  
631 - 'folder' as mime_icon_path,  
632 - 'Folder' as mime_display  
633 - FROM  
634 - folders f  
635 - INNER JOIN permission_lookups AS PL ON f.permission_lookup_id = PL.id  
636 - INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = $permissionid  
637 - LEFT OUTER JOIN users AS uc ON f.creator_id=uc.id  
638 -  
639 - WHERE  
640 - f.parent_id=$this->folderid  
641 -  
642 - AND PLA.permission_descriptor_id IN ($aPermissionDescriptors)  
643 - ORDER BY item_type DESC, title, filename  
644 - ";  
645 - }  
646 -  
647 - $contents = DBUtil::getResultArray($sql);  
648 - if (is_null($contents) || PEAR::isError($contents))  
649 - {  
650 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
651 - }  
652 -  
653 - $num_items = count($contents);  
654 - for($i=0;$i<$num_items;$i++)  
655 - {  
656 - $contents[$i]['id'] = (int) $contents[$i]['id'];  
657 - if ($contents[$i]['item_type'] == 'D')  
658 - {  
659 - $contents[$i]['items'] = array();  
660 - }  
661 - else  
662 - {  
663 - if ($depth-1 > 0)  
664 - {  
665 - $folder = &$this->ktapi->get_folder_by_id($item['id']);  
666 - $contents[$i]['items'] = $folder->get_listing($depth-1);  
667 - }  
668 - else  
669 - {  
670 - $contents[$i]['items'] = array();  
671 - }  
672 - }  
673 - }  
674 -  
675 - return $contents;  
676 - }  
677 -  
678 - /**  
679 - * This adds a document to the current folder.  
680 - *  
681 - * @access public  
682 - * @param string $title This is the title for the file in the repository.  
683 - * @param string $filename This is the filename in the system for the file.  
684 - * @param string $documenttype This is the name or id of the document type. It first looks by name, then by id.  
685 - * @param string $tempfilename This is a reference to the file that is accessible locally on the file system.  
686 - * @return KTAPI_Document  
687 - */  
688 - function &add_document($title, $filename, $documenttype, $tempfilename)  
689 - {  
690 - if (!is_file($tempfilename))  
691 - {  
692 - return new PEAR_Error('File does not exist.');  
693 - }  
694 -  
695 - $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_WRITE);  
696 - if (PEAR::isError($user))  
697 - {  
698 - return $user;  
699 - }  
700 -  
701 - $filename = basename($filename);  
702 - $documenttypeid = KTAPI::get_documenttypeid($documenttype);  
703 -  
704 - $options = array(  
705 - 'contents' => new KTFSFileLike($tempfilename),  
706 - 'novalidate' => true,  
707 - 'documenttype' => DocumentType::get($documenttypeid),  
708 - 'description' => $title,  
709 - 'metadata'=>array(),  
710 - 'cleanup_initial_file' => true  
711 - );  
712 -  
713 - DBUtil::startTransaction();  
714 - $document =& KTDocumentUtil::add($this->folder, $filename, $user, $options);  
715 -  
716 - if (!is_a($document,'Document'))  
717 - {  
718 - DBUtil::rollback();  
719 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
720 - }  
721 - DBUtil::commit();  
722 -  
723 - $tempfilename=addslashes($tempfilename);  
724 - $sql = "DELETE FROM uploaded_files WHERE tempfilename='$tempfilename'";  
725 - $result = DBUtil::runQuery($sql);  
726 - if (PEAR::isError($result))  
727 - {  
728 - return $result;  
729 - }  
730 -  
731 - return new KTAPI_Document($this->ktapi, $this, $document);  
732 - }  
733 -  
734 - /**  
735 - * This adds a subfolder folder to the current folder.  
736 - *  
737 - * @access public  
738 - * @param string $foldername  
739 - * @return KTAPI_Folder  
740 - */  
741 - function &add_folder($foldername)  
742 - {  
743 - $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_ADD_FOLDER);  
744 -  
745 - if (PEAR::isError($user))  
746 - {  
747 - return $user;  
748 - }  
749 -  
750 - DBUtil::startTransaction();  
751 - $result = KTFolderUtil::add($this->folder, $foldername, $user);  
752 -  
753 - if (PEAR::isError($result))  
754 - {  
755 - DBUtil::rollback();  
756 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
757 - }  
758 - DBUtil::commit();  
759 - $folderid = $result->getId();  
760 -  
761 - return $this->ktapi->get_folder_by_id($folderid);  
762 - }  
763 -  
764 - /**  
765 - * This deletes the current folder.  
766 - *  
767 - * @param string $reason  
768 - */  
769 - function delete($reason)  
770 - {  
771 - $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_DELETE);  
772 - if (PEAR::isError($user))  
773 - {  
774 - return $user;  
775 - }  
776 -  
777 - if ($this->folderid == 1)  
778 - {  
779 - return new PEAR_Error('Cannot delete root folder!');  
780 - }  
781 -  
782 - DBUtil::startTransaction();  
783 - $result = KTFolderUtil::delete($this->folder, $user, $reason);  
784 -  
785 - if (PEAR::isError($result))  
786 - {  
787 - DBUtil::rollback();  
788 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
789 - }  
790 - DBUtil::commit();  
791 - }  
792 -  
793 - /**  
794 - * This renames the folder  
795 - *  
796 - * @param string $newname  
797 - */  
798 - function rename($newname)  
799 - {  
800 - $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_RENAME_FOLDER);  
801 - if (PEAR::isError($user))  
802 - {  
803 - return $user;  
804 - }  
805 -  
806 - DBUtil::startTransaction();  
807 - $result = KTFolderUtil::rename($this->folder, $newname, $user);  
808 -  
809 - if (PEAR::isError($result))  
810 - {  
811 - DBUtil::rollback();  
812 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
813 - }  
814 - DBUtil::commit();  
815 - }  
816 -  
817 - /**  
818 - * This moves the folder to another location.  
819 - *  
820 - * @param KTAPI_Folder $ktapi_target_folder  
821 - * @param string $reason  
822 - */  
823 - function move($ktapi_target_folder, $reason='')  
824 - {  
825 - assert(!is_null($ktapi_target_folder));  
826 - assert(is_a($ktapi_target_folder,'KTAPI_Folder'));  
827 -  
828 - $user = $this->ktapi->get_user();  
829 -  
830 - $target_folder = $ktapi_target_folder->get_folder();  
831 -  
832 - $result = $this->can_user_access_object_requiring_permission($target_folder, KTAPI_PERMISSION_WRITE);  
833 - if (PEAR::isError($result))  
834 - {  
835 - return $result;  
836 - }  
837 -  
838 - DBUtil::startTransaction();  
839 - $result = KTFolderUtil::copy($this->folder, $target_folder, $user, $reason);  
840 -  
841 - if (PEAR::isError($result))  
842 - {  
843 - DBUtil::rollback();  
844 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
845 - }  
846 - DBUtil::commit();  
847 - }  
848 -  
849 - /**  
850 - * This copies a folder to another location.  
851 - *  
852 - * @param KTAPI_Folder $ktapi_target_folder  
853 - * @param string $reason  
854 - */  
855 - function copy($ktapi_target_folder, $reason='')  
856 - {  
857 - assert(!is_null($ktapi_target_folder));  
858 - assert(is_a($ktapi_target_folder,'KTAPI_Folder'));  
859 -  
860 - $user = $this->ktapi->get_user();  
861 -  
862 - $target_folder = $ktapi_target_folder->get_folder();  
863 -  
864 - $result =$this->can_user_access_object_requiring_permission($target_folder, KTAPI_PERMISSION_WRITE);  
865 -  
866 - if (PEAR::isError($result))  
867 - {  
868 - return $result;  
869 - }  
870 -  
871 - DBUtil::startTransaction();  
872 - $result = KTFolderUtil::copy($this->folder, $target_folder, $user, $reason);  
873 -  
874 - if (PEAR::isError($result))  
875 - {  
876 - DBUtil::rollback();  
877 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
878 - }  
879 - DBUtil::commit();  
880 - }  
881 -  
882 - /**  
883 - * This returns all permissions linked to the folder.  
884 - *  
885 - * @access public  
886 - * @return array  
887 - */  
888 - function get_permissions()  
889 - {  
890 - return new PEAR_Error('TODO');  
891 - }  
892 -  
893 - /**  
894 - * This returns a transaction history listing.  
895 - *  
896 - * @access public  
897 - * @return array  
898 - */  
899 - function get_transaction_history()  
900 - {  
901 - return new PEAR_Error('TODO');  
902 - }  
903 -}  
904 -  
905 -class KTAPI_Document extends KTAPI_FolderItem  
906 -{  
907 - /**  
908 - * This is a reference to the internal document object.  
909 - *  
910 - * @var Document  
911 - */  
912 - var $document;  
913 - /**  
914 - * This is the id of the document.  
915 - *  
916 - * @var int  
917 - */  
918 - var $documentid;  
919 - /**  
920 - * This is a reference to the parent folder.  
921 - *  
922 - * @var KTAPI_Folder  
923 - */  
924 - var $ktapi_folder;  
925 -  
926 - /**  
927 - * This is used to get a document based on document id.  
928 - *  
929 - * @static  
930 - * @access public  
931 - * @param KTAPI $ktapi  
932 - * @param int $documentid  
933 - * @return KTAPI_Document  
934 - */  
935 - function &get(&$ktapi, $documentid)  
936 - {  
937 - assert(!is_null($ktapi));  
938 - assert(is_a($ktapi, 'KTAPI'));  
939 - assert(is_numeric($documentid));  
940 -  
941 - $documentid += 0;  
942 -  
943 - $document = &Document::get($documentid);  
944 - if (is_null($document) || PEAR::isError($document))  
945 - {  
946 - return new PEAR_Error(KTAPI_ERROR_DOCUMENT_INVALID);  
947 - }  
948 -  
949 - $user = $ktapi->can_user_access_object_requiring_permission($document, KTAPI_PERMISSION_READ);  
950 -  
951 - if (is_null($user) || PEAR::isError($user))  
952 - {  
953 - return $user;  
954 - }  
955 -  
956 - $folderid = $document->getParentID();  
957 -  
958 - if (!is_null($folderid))  
959 - {  
960 - $ktapi_folder = &KTAPI_Folder::get($ktapi, $folderid);  
961 - }  
962 - else  
963 - {  
964 - $ktapi_folder = null;  
965 - }  
966 - // We don't do any checks on this folder as it could possibly be deleted, and is not required right now.  
967 -  
968 - return new KTAPI_Document($ktapi, $ktapi_folder, $document);  
969 - }  
970 -  
971 - /**  
972 - * This is the constructor for the KTAPI_Folder.  
973 - *  
974 - * @access private  
975 - * @param KTAPI $ktapi  
976 - * @param Document $document  
977 - * @return KTAPI_Document  
978 - */  
979 - function KTAPI_Document(&$ktapi, &$ktapi_folder, &$document)  
980 - {  
981 - assert(is_a($ktapi,'KTAPI'));  
982 - assert(is_null($ktapi_folder) || is_a($ktapi_folder,'KTAPI_Folder'));  
983 -  
984 - $this->ktapi = &$ktapi;  
985 - $this->ktapi_folder = &$ktapi_folder;  
986 - $this->document = &$document;  
987 - $this->documentid = $document->getId();  
988 - }  
989 -  
990 - /**  
991 - * This checks a document into the repository  
992 - *  
993 - * @param string $filename  
994 - * @param string $reason  
995 - * @param string $tempfilename  
996 - * @param bool $major_update  
997 - */  
998 - function checkin($filename, $reason, $tempfilename, $major_update=false)  
999 - {  
1000 - if (!is_file($tempfilename))  
1001 - {  
1002 - return new PEAR_Error('File does not exist.');  
1003 - }  
1004 -  
1005 - $user = $this->can_user_access_object_requiring_permission($this->document, KTAPI_PERMISSION_WRITE);  
1006 -  
1007 - if (PEAR::isError($user))  
1008 - {  
1009 - return $user;  
1010 - }  
1011 -  
1012 - if (!$this->document->getIsCheckedOut())  
1013 - {  
1014 - return new PEAR_Error(KTAPI_ERROR_DOCUMENT_NOT_CHECKED_OUT);  
1015 - }  
1016 -  
1017 - $options = array('major_update'=>$major_update);  
1018 -  
1019 - $currentfilename = $this->document->getFileName();  
1020 - if ($filename != $currentfilename)  
1021 - {  
1022 - $options['newfilename'] = $filename;  
1023 - }  
1024 -  
1025 - DBUtil::startTransaction();  
1026 - $result = KTDocumentUtil::checkin($this->document, $tempfilename, $reason, $user, $options);  
1027 -  
1028 - if (PEAR::isError($result))  
1029 - {  
1030 - DBUtil::rollback();  
1031 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1032 - }  
1033 - DBUtil::commit();  
1034 -  
1035 - $tempfilename=addslashes($tempfilename);  
1036 - $sql = "DELETE FROM uploaded_files WHERE tempfilename='$tempfilename'";  
1037 - $result = DBUtil::runQuery($sql);  
1038 - if (PEAR::isError($result))  
1039 - {  
1040 - return $result;  
1041 - }  
1042 -  
1043 - }  
1044 -  
1045 - /**  
1046 - * This reverses the checkout process.  
1047 - *  
1048 - * @param string $reason  
1049 - */  
1050 - function undo_checkout($reason)  
1051 - {  
1052 - $user = $this->can_user_access_object_requiring_permission($this->document, KTAPI_PERMISSION_WRITE);  
1053 -  
1054 - if (PEAR::isError($user))  
1055 - {  
1056 - return $user;  
1057 - }  
1058 -  
1059 - if (!$this->document->getIsCheckedOut())  
1060 - {  
1061 - return new PEAR_Error(KTAPI_ERROR_DOCUMENT_NOT_CHECKED_OUT);  
1062 - }  
1063 -  
1064 - DBUtil::startTransaction();  
1065 -  
1066 - $this->document->setIsCheckedOut(0);  
1067 - $this->document->setCheckedOutUserID(-1);  
1068 - $res = $this->document->update();  
1069 - if (($res === false) || PEAR::isError($res))  
1070 - {  
1071 - DBUtil::rollback();  
1072 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1073 - }  
1074 -  
1075 - $oDocumentTransaction = & new DocumentTransaction($this->document, $reason, 'ktcore.transactions.force_checkin');  
1076 -  
1077 - $res = $oDocumentTransaction->create();  
1078 - if (($res === false) || PEAR::isError($res)) {  
1079 - DBUtil::rollback();  
1080 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1081 - }  
1082 - DBUtil::commit();  
1083 - }  
1084 -  
1085 - /**  
1086 - * This returns a URL to the file that can be downloaded.  
1087 - *  
1088 - * @param string $reason  
1089 - */  
1090 - function checkout($reason)  
1091 - {  
1092 - $user = $this->can_user_access_object_requiring_permission($this->document, KTAPI_PERMISSION_WRITE);  
1093 -  
1094 - if (PEAR::isError($user))  
1095 - {  
1096 - return $user;  
1097 - }  
1098 -  
1099 - if ($this->document->getIsCheckedOut())  
1100 - {  
1101 - return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT);  
1102 - }  
1103 -  
1104 - DBUtil::startTransaction();  
1105 - $res = KTDocumentUtil::checkout($this->document, $reason, $user);  
1106 - if (PEAR::isError($res))  
1107 - {  
1108 - DBUtil::rollback();  
1109 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1110 - }  
1111 -  
1112 - DBUtil::commit();  
1113 - }  
1114 -  
1115 - /**  
1116 - * This deletes a document from the folder.  
1117 - *  
1118 - * @param string $reason  
1119 - */  
1120 - function delete($reason)  
1121 - {  
1122 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_DELETE);  
1123 -  
1124 - if (PEAR::isError($user))  
1125 - {  
1126 - return $user;  
1127 - }  
1128 -  
1129 - if ($this->document->getIsCheckedOut())  
1130 - {  
1131 - return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT);  
1132 - }  
1133 -  
1134 - DBUtil::startTransaction();  
1135 - $res = KTDocumentUtil::delete($this->document, $reason);  
1136 - if (PEAR::isError($res))  
1137 - {  
1138 - DBUtil::rollback();  
1139 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1140 - }  
1141 -  
1142 - DBUtil::commit();  
1143 - }  
1144 -  
1145 - /**  
1146 - * This changes the owner of the file.  
1147 - *  
1148 - * @param string $ktapi_newuser  
1149 - */  
1150 - function change_owner($newusername, $reason='Changing of owner.')  
1151 - {  
1152 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_CHANGE_OWNERSHIP);  
1153 -  
1154 - if (PEAR::isError($user))  
1155 - {  
1156 - return $user;  
1157 - }  
1158 -  
1159 - DBUtil::startTransaction();  
1160 -  
1161 - $user = &User::getByUserName($newusername);  
1162 - if (is_null($user) || PEAR::isError($user))  
1163 - {  
1164 - return new PEAR_Error('User could not be found');  
1165 - }  
1166 -  
1167 - $newuserid = $user->getId();  
1168 -  
1169 - $this->document->setOwnerID($newuserid);  
1170 -  
1171 - $res = $this->document->update();  
1172 -  
1173 - if (PEAR::isError($res))  
1174 - {  
1175 - DBUtil::rollback();  
1176 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1177 - }  
1178 -  
1179 - $res = KTPermissionUtil::updatePermissionLookup($this->document);  
1180 - if (PEAR::isError($res))  
1181 - {  
1182 - DBUtil::rollback();  
1183 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1184 - }  
1185 -  
1186 - $oDocumentTransaction = & new DocumentTransaction($this->document, $reason, 'ktcore.transactions.permissions_change');  
1187 -  
1188 - $res = $oDocumentTransaction->create();  
1189 - if (($res === false) || PEAR::isError($res)) {  
1190 - DBUtil::rollback();  
1191 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1192 - }  
1193 -  
1194 - DBUtil::commit();  
1195 - }  
1196 -  
1197 - /**  
1198 - * This copies the document to another folder.  
1199 - *  
1200 - * @param KTAPI_Folder $ktapi_target_folder  
1201 - * @param string $reason  
1202 - * @param string $newname  
1203 - * @param string $newfilename  
1204 - */  
1205 - function copy(&$ktapi_target_folder, $reason, $newname=null, $newfilename=null)  
1206 - {  
1207 - assert(!is_null($ktapi_target_folder));  
1208 - assert(is_a($ktapi_target_folder,'KTAPI_Folder'));  
1209 -  
1210 - if (empty($newname))  
1211 - {  
1212 - $newname=null;  
1213 - }  
1214 - if (empty($newfilename))  
1215 - {  
1216 - $newfilename=null;  
1217 - }  
1218 -  
1219 - $user = $this->ktapi->get_user();  
1220 -  
1221 - if ($this->document->getIsCheckedOut())  
1222 - {  
1223 - return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT);  
1224 - }  
1225 -  
1226 - $target_folder = &$ktapi_target_folder->get_folder();  
1227 -  
1228 - $result = $this->can_user_access_object_requiring_permission( $target_folder, KTAPI_PERMISSION_WRITE);  
1229 -  
1230 - if (PEAR::isError($result))  
1231 - {  
1232 - return $result;  
1233 - }  
1234 -  
1235 - $name = $this->document->getName();  
1236 - $clash = KTDocumentUtil::nameExists($target_folder, $name);  
1237 - if ($clash && !is_null($newname))  
1238 - {  
1239 - $name = $newname;  
1240 - $clash = KTDocumentUtil::nameExists($target_folder, $name);  
1241 - }  
1242 - if ($clash)  
1243 - {  
1244 - return new PEAR_Error('A document with this title already exists in your chosen folder. Please choose a different folder, or specify a new title for the copied document.');  
1245 - }  
1246 -  
1247 - $filename=$this->document->getFilename();  
1248 - $clash = KTDocumentUtil::fileExists($target_folder, $filename);  
1249 -  
1250 - if ($clash && !is_null($newname))  
1251 - {  
1252 - $filename = $newfilename;  
1253 - $clash = KTDocumentUtil::fileExists($target_folder, $filename);  
1254 - }  
1255 - if ($clash)  
1256 - {  
1257 - return new PEAR_Error('A document with this filename already exists in your chosen folder. Please choose a different folder, or specify a new filename for the copied document.');  
1258 - }  
1259 -  
1260 - DBUtil::startTransaction();  
1261 -  
1262 - $new_document = KTDocumentUtil::copy($this->document, $target_folder, $reason);  
1263 - if (PEAR::isError($new_document))  
1264 - {  
1265 - DBUtil::rollback();  
1266 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1267 - }  
1268 -  
1269 - $new_document->setName($name);  
1270 - $new_document->setFilename($filename);  
1271 -  
1272 - $res = $new_document->update();  
1273 -  
1274 - if (PEAR::isError($res))  
1275 - {  
1276 - DBUtil::rollback();  
1277 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1278 - }  
1279 -  
1280 - DBUtil::commit();  
1281 -  
1282 - // FIXME do we need to refactor all trigger usage into the util function?  
1283 - $oKTTriggerRegistry = KTTriggerRegistry::getSingleton();  
1284 - $aTriggers = $oKTTriggerRegistry->getTriggers('copyDocument', 'postValidate');  
1285 - foreach ($aTriggers as $aTrigger) {  
1286 - $sTrigger = $aTrigger[0];  
1287 - $oTrigger = new $sTrigger;  
1288 - $aInfo = array(  
1289 - 'document' => $new_document,  
1290 - 'old_folder' => $this->folder->get_folder(),  
1291 - 'new_folder' => $target_folder,  
1292 - );  
1293 - $oTrigger->setInfo($aInfo);  
1294 - $ret = $oTrigger->postValidate();  
1295 - }  
1296 - }  
1297 -  
1298 - /**  
1299 - * This moves the document to another folder.  
1300 - *  
1301 - * @param KTAPI_Folder $ktapi_target_folder  
1302 - * @param string $reason  
1303 - * @param string $newname  
1304 - * @param string $newfilename  
1305 - */  
1306 - function move(&$ktapi_target_folder, $reason, $newname=null, $newfilename=null)  
1307 - {  
1308 - assert(!is_null($ktapi_target_folder));  
1309 - assert(is_a($ktapi_target_folder,'KTAPI_Folder'));  
1310 -  
1311 - if (empty($newname))  
1312 - {  
1313 - $newname=null;  
1314 - }  
1315 - if (empty($newfilename))  
1316 - {  
1317 - $newfilename=null;  
1318 - }  
1319 -  
1320 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_DOCUMENT_MOVE);  
1321 -  
1322 - if (PEAR::isError($user))  
1323 - {  
1324 - return $user;  
1325 - }  
1326 -  
1327 - if ($this->document->getIsCheckedOut())  
1328 - {  
1329 - return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT);  
1330 - }  
1331 -  
1332 - $target_folder = $ktapi_target_folder->get_folder();  
1333 -  
1334 - $result= $this->can_user_access_object_requiring_permission( $target_folder, KTAPI_PERMISSION_WRITE);  
1335 -  
1336 - if (PEAR::isError($result))  
1337 - {  
1338 - return $result;  
1339 - }  
1340 -  
1341 - if (!KTDocumentUtil::canBeMoved($this->document))  
1342 - {  
1343 - return new PEAR_Error('Document cannot be moved.');  
1344 - }  
1345 -  
1346 - $name = $this->document->getName();  
1347 - $clash = KTDocumentUtil::nameExists($target_folder, $name);  
1348 - if ($clash && !is_null($newname))  
1349 - {  
1350 - $name = $newname;  
1351 - $clash = KTDocumentUtil::nameExists($target_folder, $name);  
1352 - }  
1353 - if ($clash)  
1354 - {  
1355 - return new PEAR_Error('A document with this title already exists in your chosen folder. Please choose a different folder, or specify a new title for the moved document.');  
1356 - }  
1357 -  
1358 - $filename=$this->document->getFilename();  
1359 - $clash = KTDocumentUtil::fileExists($target_folder, $filename);  
1360 -  
1361 - if ($clash && !is_null($newname))  
1362 - {  
1363 - $filename = $newfilename;  
1364 - $clash = KTDocumentUtil::fileExists($target_folder, $filename);  
1365 - }  
1366 - if ($clash)  
1367 - {  
1368 - return new PEAR_Error('A document with this filename already exists in your chosen folder. Please choose a different folder, or specify a new filename for the moved document.');  
1369 - }  
1370 -  
1371 - DBUtil::startTransaction();  
1372 -  
1373 - $res = KTDocumentUtil::move($this->document, $target_folder, $user, $reason);  
1374 - if (PEAR::isError($res))  
1375 - {  
1376 - DBUtil::rollback();  
1377 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1378 - }  
1379 -  
1380 - $this->document->setName($name);  
1381 - $this->document->setFilename($filename);  
1382 -  
1383 - $res = $this->document->update();  
1384 -  
1385 - if (PEAR::isError($res))  
1386 - {  
1387 - DBUtil::rollback();  
1388 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1389 - }  
1390 -  
1391 - DBUtil::commit();  
1392 - }  
1393 -  
1394 - /**  
1395 - * This changes the filename of the document.  
1396 - *  
1397 - * @param string $newname  
1398 - */  
1399 - function renameFile($newname)  
1400 - {  
1401 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE);  
1402 -  
1403 - if (PEAR::isError($user))  
1404 - {  
1405 - return $user;  
1406 - }  
1407 -  
1408 - DBUtil::startTransaction();  
1409 - $res = KTDocumentUtil::rename($this->document, $newname, $user);  
1410 - if (PEAR::isError($res))  
1411 - {  
1412 - DBUtil::rollback();  
1413 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1414 - }  
1415 - DBUtil::commit();  
1416 - }  
1417 -  
1418 - /**  
1419 - * This changes the document type of the document.  
1420 - *  
1421 - * @param string $newname  
1422 - */  
1423 - function change_document_type($documenttype)  
1424 - {  
1425 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE);  
1426 -  
1427 - if (PEAR::isError($user))  
1428 - {  
1429 - return $user;  
1430 - }  
1431 -  
1432 - $doctypeid = KTAPI::get_documenttypeid($documenttype);  
1433 -  
1434 - if ($this->document->getDocumentTypeId() != $doctypeid)  
1435 - {  
1436 - DBUtil::startTransaction();  
1437 - $this->document->setDocumentTypeId($doctypeid);  
1438 - $res = $this->document->update();  
1439 -  
1440 - if (PEAR::isError($res))  
1441 - {  
1442 - DBUtil::rollback();  
1443 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1444 - }  
1445 - DBUtil::commit();  
1446 - }  
1447 - }  
1448 -  
1449 - /**  
1450 - * This changes the title of the document.  
1451 - *  
1452 - * @param string $newname  
1453 - */  
1454 - function rename($newname)  
1455 - {  
1456 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE);  
1457 -  
1458 - if (PEAR::isError($user))  
1459 - {  
1460 - return $user;  
1461 - }  
1462 -  
1463 - if ($this->document->getName() != $newname)  
1464 - {  
1465 -  
1466 - DBUtil::startTransaction();  
1467 - $this->document->setName($newname);  
1468 - $res = $this->document->update();  
1469 -  
1470 - if (PEAR::isError($res))  
1471 - {  
1472 - DBUtil::rollback();  
1473 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1474 - }  
1475 - DBUtil::commit();  
1476 - }  
1477 - }  
1478 -  
1479 - /**  
1480 - * This flags the document as 'archived'.  
1481 - *  
1482 - * @param string $reason  
1483 - */  
1484 - function archive($reason)  
1485 - {  
1486 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE);  
1487 -  
1488 - if (PEAR::isError($user))  
1489 - {  
1490 - return $user;  
1491 - }  
1492 -  
1493 - list($permission, $user) = $perm_and_user;  
1494 -  
1495 - DBUtil::startTransaction();  
1496 - $this->document->setStatusID(ARCHIVED);  
1497 - $res = $this->document->update();  
1498 - if (($res === false) || PEAR::isError($res)) {  
1499 - DBUtil::rollback();  
1500 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1501 - }  
1502 -  
1503 - $oDocumentTransaction = & new DocumentTransaction($this->document, sprintf(_kt('Document archived: %s'), $reason), 'ktcore.transactions.update');  
1504 - $oDocumentTransaction->create();  
1505 -  
1506 - DBUtil::commit();  
1507 -  
1508 - $oKTTriggerRegistry = KTTriggerRegistry::getSingleton();  
1509 - $aTriggers = $oKTTriggerRegistry->getTriggers('archive', 'postValidate');  
1510 - foreach ($aTriggers as $aTrigger)  
1511 - {  
1512 - $sTrigger = $aTrigger[0];  
1513 - $oTrigger = new $sTrigger;  
1514 - $aInfo = array(  
1515 - 'document' => $this->document,  
1516 - );  
1517 - $oTrigger->setInfo($aInfo);  
1518 - $ret = $oTrigger->postValidate();  
1519 - }  
1520 - }  
1521 -  
1522 - /**  
1523 - * This starts a workflow on a document.  
1524 - *  
1525 - * @param string $workflow  
1526 - */  
1527 - function start_workflow($workflow)  
1528 - {  
1529 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW);  
1530 -  
1531 - if (PEAR::isError($user))  
1532 - {  
1533 - return $user;  
1534 - }  
1535 -  
1536 - $workflowid = $this->document->getWorkflowId();  
1537 -  
1538 - if (!empty($workflowid))  
1539 - {  
1540 - return new PEAR_Error('A workflow is already defined.');  
1541 - }  
1542 -  
1543 - $workflow = KTWorkflow::getByName($workflow);  
1544 - if (is_null($workflow) || PEAR::isError($workflow))  
1545 - {  
1546 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_INVALID);  
1547 - }  
1548 -  
1549 - DBUtil::startTransaction();  
1550 - $result = KTWorkflowUtil::startWorkflowOnDocument($workflow, $this->document);  
1551 - if (is_null($result) || PEAR::isError($result))  
1552 - {  
1553 - DBUtil::rollback();  
1554 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_INVALID);  
1555 - }  
1556 - DBUtil::commit();  
1557 - }  
1558 -  
1559 - /**  
1560 - * This deletes the workflow on the document.  
1561 - *  
1562 - */  
1563 - function delete_workflow()  
1564 - {  
1565 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW);  
1566 -  
1567 - if (PEAR::isError($user))  
1568 - {  
1569 - return $user;  
1570 - }  
1571 -  
1572 - $workflowid=$this->document->getWorkflowId();  
1573 - if (!empty($workflowid))  
1574 - {  
1575 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS);  
1576 - }  
1577 -  
1578 - DBUtil::startTransaction();  
1579 - $result = KTWorkflowUtil::startWorkflowOnDocument(null, $this->document);  
1580 - if (is_null($result) || PEAR::isError($result))  
1581 - {  
1582 - DBUtil::rollback();  
1583 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_INVALID);  
1584 - }  
1585 - DBUtil::commit();  
1586 - }  
1587 -  
1588 - /**  
1589 - * This performs a transition on the workflow  
1590 - *  
1591 - * @param string $transition  
1592 - * @param string $reason  
1593 - */  
1594 - function perform_workflow_transition($transition, $reason)  
1595 - {  
1596 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW);  
1597 -  
1598 - if (PEAR::isError($user))  
1599 - {  
1600 - return $user;  
1601 - }  
1602 -  
1603 - $workflowid=$this->document->getWorkflowId();  
1604 - if (empty($workflowid))  
1605 - {  
1606 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS);  
1607 - }  
1608 -  
1609 - $transition = &KTWorkflowTransition::getByName($transition);  
1610 - if (is_null($transition) || PEAR::isError($transition))  
1611 - {  
1612 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_INVALID);  
1613 - }  
1614 -  
1615 - DBUtil::startTransaction();  
1616 - $result = KTWorkflowUtil::performTransitionOnDocument($transition, $this->document, $user, $reason);  
1617 - if (is_null($result) || PEAR::isError($result))  
1618 - {  
1619 - DBUtil::rollback();  
1620 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_INVALID);  
1621 - }  
1622 - DBUtil::commit();  
1623 - }  
1624 -  
1625 -  
1626 -  
1627 - /**  
1628 - * This returns all metadata for the document.  
1629 - *  
1630 - * @return array  
1631 - */  
1632 - function get_metadata()  
1633 - {  
1634 - $doctypeid = $this->document->getDocumentTypeID();  
1635 - $fieldsets = (array) KTMetadataUtil::fieldsetsForDocument($this->document, $doctypeid);  
1636 -  
1637 - $results = array();  
1638 -  
1639 - foreach ($fieldsets as $fieldset)  
1640 - {  
1641 - if ($fieldset->getIsConditional()) { /* this is not implemented...*/ continue; }  
1642 -  
1643 - $fields = $fieldset->getFields();  
1644 - $result = array('fieldset' => $fieldset->getName(),  
1645 - 'description' => $fieldset->getDescription());  
1646 -  
1647 - $fieldsresult = array();  
1648 -  
1649 - foreach ($fields as $field)  
1650 - {  
1651 - $value = 'n/a';  
1652 -  
1653 - $fieldvalue = DocumentFieldLink::getByDocumentAndField($this->document, $field);  
1654 - if (!is_null($fieldvalue) && (!PEAR::isError($fieldvalue)))  
1655 - {  
1656 - $value = $fieldvalue->getValue();  
1657 - }  
1658 -  
1659 - $controltype = 'string';  
1660 - if ($field->getHasLookup())  
1661 - {  
1662 - $controltype = 'lookup';  
1663 - if ($field->getHasLookupTree())  
1664 - {  
1665 - $controltype = 'tree';  
1666 - }  
1667 - }  
1668 -  
1669 - switch ($controltype)  
1670 - {  
1671 - case 'lookup':  
1672 - $selection = KTAPI::get_metadata_lookup($field->getId());  
1673 - break;  
1674 - case 'tree':  
1675 - $selection = KTAPI::get_metadata_tree($field->getId());  
1676 - break;  
1677 - default:  
1678 - $selection= array();  
1679 - }  
1680 -  
1681 -  
1682 - $fieldsresult[] = array(  
1683 - 'name' => $field->getName(),  
1684 - 'required' => $field->getIsMandatory(),  
1685 - 'value' => $value,  
1686 - 'description' => $field->getDescription(),  
1687 - 'control_type' => $controltype,  
1688 - 'selection' => $selection  
1689 -  
1690 - );  
1691 -  
1692 - }  
1693 - $result['fields'] = $fieldsresult;  
1694 - $results [] = $result;  
1695 - }  
1696 -  
1697 - return $results;  
1698 - }  
1699 -  
1700 - /**  
1701 - * This updates the metadata on the file. This includes the 'title'.  
1702 - *  
1703 - * @param array This is an array containing the metadata to be associated with the file.  
1704 - */  
1705 - function update_metadata($metadata)  
1706 - {  
1707 - $packed = array();  
1708 -  
1709 - foreach($metadata as $fieldset_metadata)  
1710 - {  
1711 - $fieldsetname=$fieldset_metadata['fieldset'];  
1712 - $fieldset = KTFieldset::getByName($fieldsetname);  
1713 - if (is_null($fieldset) || PEAR::isError($fieldset))  
1714 - {  
1715 - // exit graciously  
1716 - continue;  
1717 - }  
1718 -  
1719 - foreach($fieldset_metadata['fields'] as $fieldinfo)  
1720 - {  
1721 - $fieldname = $fieldinfo['name'];  
1722 - $field = DocumentField::getByFieldsetAndName($fieldset, $fieldname);  
1723 - if (is_null($field) || PEAR::isError($fieldset))  
1724 - {  
1725 - // exit graciously  
1726 - continue;  
1727 - }  
1728 - $value = $fieldinfo['value'];  
1729 -  
1730 - $packed[] = array($field, $value);  
1731 - }  
1732 - }  
1733 -  
1734 - DBUtil::startTransaction();  
1735 - $result = KTDocumentUtil::saveMetadata($this->document, $packed);  
1736 -  
1737 - if (is_null($result))  
1738 - {  
1739 - DBUtil::rollback();  
1740 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1741 - }  
1742 - if (PEAR::isError($result))  
1743 - {  
1744 - DBUtil::rollback();  
1745 - return new PEAR_Error(sprintf(_kt("Unexpected validation failure: %s."), $result->getMessage()));  
1746 - }  
1747 - DBUtil::commit();  
1748 - }  
1749 -  
1750 -  
1751 - /**  
1752 - * This returns a workflow transition  
1753 - *  
1754 - * @return array  
1755 - */  
1756 - function get_workflow_transitions()  
1757 - {  
1758 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW);  
1759 -  
1760 - if (PEAR::isError($user))  
1761 - {  
1762 - return $user;  
1763 - }  
1764 -  
1765 - $workflowid=$this->document->getWorkflowId();  
1766 - if (empty($workflowid))  
1767 - {  
1768 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS);  
1769 - }  
1770 -  
1771 - $result = array();  
1772 -  
1773 - $transitions = KTWorkflowUtil::getTransitionsForDocumentUser($this->document, $user);  
1774 - if (is_null($transitions) || PEAR::isError($transitions))  
1775 - {  
1776 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_INVALID);  
1777 - }  
1778 - foreach($transitions as $transition)  
1779 - {  
1780 - $result[] = $transition->getName();  
1781 - }  
1782 -  
1783 - return $result;  
1784 - }  
1785 -  
1786 - /**  
1787 - * This returns the current workflow state  
1788 - *  
1789 - * @return string  
1790 - */  
1791 - function get_workflow_state()  
1792 - {  
1793 - $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW);  
1794 -  
1795 - if (PEAR::isError($user))  
1796 - {  
1797 - return $user;  
1798 - }  
1799 -  
1800 - $workflowid=$this->document->getWorkflowId();  
1801 - if (empty($workflowid))  
1802 - {  
1803 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS);  
1804 - }  
1805 -  
1806 - $result = array();  
1807 -  
1808 - $state = KTWorkflowUtil::getWorkflowStateForDocument($this->document);  
1809 - if (is_null($state) || PEAR::isError($state))  
1810 - {  
1811 - return new PEAR_Error(KTAPI_ERROR_WORKFLOW_INVALID);  
1812 - }  
1813 -  
1814 - $statename = $state->getName();  
1815 -  
1816 - return $statename;  
1817 -  
1818 - }  
1819 -  
1820 - /**  
1821 - * This returns detailed information on the document.  
1822 - *  
1823 - * @return array  
1824 - */  
1825 - function get_detail()  
1826 - {  
1827 - $detail = array();  
1828 - $document = $this->document;  
1829 -  
1830 - $detail['title'] = $document->getName();  
1831 -  
1832 - $documenttypeid=$document->getDocumentTypeID();  
1833 - if (is_numeric($documenttypeid))  
1834 - {  
1835 - $documenttype = DocumentType::get($documenttypeid);  
1836 -  
1837 - $documenttype=$documenttype->getName();  
1838 - }  
1839 - else  
1840 - {  
1841 - $documenttype = '* unknown *';  
1842 - }  
1843 - $detail['document_type'] = $documenttype;  
1844 -  
1845 - $detail['version'] = $document->getVersion();  
1846 - $detail['filename'] = $document->getFilename();  
1847 -  
1848 - $detail['created_date'] = $document->getCreatedDateTime();  
1849 -  
1850 - $userid = $document->getCreatorID();  
1851 - if (is_numeric($userid))  
1852 - {  
1853 - $user = User::get($userid);  
1854 - $username=(is_null($user) || PEAR::isError($user))?'* unknown *':$user->getName();  
1855 - }  
1856 - else  
1857 - {  
1858 - $username='n/a';  
1859 - }  
1860 - $detail['created_by'] = $username;  
1861 - $detail['updated_date'] = $document->getLastModifiedDate();  
1862 -  
1863 - $userid = $document->getModifiedUserId();  
1864 - if (is_numeric($userid))  
1865 - {  
1866 - $user = User::get($userid);  
1867 - $username=(is_null($user) || PEAR::isError($user))?'* unknown *':$user->getName();  
1868 - }  
1869 - else  
1870 - {  
1871 - $username='n/a';  
1872 - }  
1873 - $detail['updated_by'] = $username;  
1874 - $detail['document_id'] = (int) $document->getId();  
1875 - $detail['folder_id'] = (int) $document->getFolderID();  
1876 -  
1877 - $workflowid = $document->getWorkflowId();  
1878 - if (is_numeric($workflowid))  
1879 - {  
1880 - $workflow = KTWorkflow::get($workflowid);  
1881 - $workflowname=(is_null($workflow) || PEAR::isError($workflow))?'* unknown *':$workflow->getName();  
1882 - }  
1883 - else  
1884 - {  
1885 - $workflowname='n/a';  
1886 - }  
1887 - $detail['workflow'] = $workflowname;  
1888 -  
1889 - $stateid = $document->getWorkflowStateId();  
1890 - if (is_numeric($stateid))  
1891 - {  
1892 - $state = KTWorkflowState::get($stateid);  
1893 - $workflowstate=(is_null($state) || PEAR::isError($state))?'* unknown *':$state->getName();  
1894 - }  
1895 - else  
1896 - {  
1897 - $workflowstate = 'n/a';  
1898 - }  
1899 - $detail['workflow_state']=$workflowstate;  
1900 -  
1901 - $userid = $document->getCheckedOutUserID();  
1902 -  
1903 - if (is_numeric($userid))  
1904 - {  
1905 - $user = User::get($userid);  
1906 - $username=(is_null($user) || PEAR::isError($user))?'* unknown *':$user->getName();  
1907 - }  
1908 - else  
1909 - {  
1910 - $username = 'n/a';  
1911 - }  
1912 - $detail['checkout_by'] = $username;  
1913 -  
1914 - $detail['full_path'] = $this->ktapi_folder->get_full_path() . '/' . $this->get_title();  
1915 -  
1916 - return $detail;  
1917 - }  
1918 -  
1919 - function get_title()  
1920 - {  
1921 - return $this->document->getDescription();  
1922 - }  
1923 -  
1924 - /**  
1925 - * This does a download of a version of the document.  
1926 - *  
1927 - * @param string $version  
1928 - */  
1929 - function download($version=null)  
1930 - {  
1931 - $storage =& KTStorageManagerUtil::getSingleton();  
1932 - $options = array(); 38 +require_once('KTAPIConstants.inc.php');
  39 +require_once('KTAPISession.inc.php');
  40 +require_once('KTAPIFolder.inc.php');
  41 +require_once('KTAPIDocument.inc.php');
1933 42
1934 -  
1935 - $oDocumentTransaction = & new DocumentTransaction($this->document, 'Document downloaded', 'ktcore.transactions.download', $aOptions);  
1936 - $oDocumentTransaction->create();  
1937 - }  
1938 - 43 +class KTAPI_FolderItem
  44 +{
1939 /** 45 /**
1940 - * This returns the transaction history for the document. 46 + * This is a reference to the core KTAPI controller
1941 * 47 *
1942 - * @return array 48 + * @access protected
  49 + * @var KTAPI
1943 */ 50 */
1944 - function get_transaction_history()  
1945 - {  
1946 - $sQuery = 'SELECT DTT.name AS transaction_name, U.name AS username, DT.version AS version, DT.comment AS comment, DT.datetime AS datetime ' .  
1947 - 'FROM ' . KTUtil::getTableName('document_transactions') . ' AS DT INNER JOIN ' . KTUtil::getTableName('users') . ' AS U ON DT.user_id = U.id ' .  
1948 - 'INNER JOIN ' . KTUtil::getTableName('transaction_types') . ' AS DTT ON DTT.namespace = DT.transaction_namespace ' .  
1949 - 'WHERE DT.document_id = ? ORDER BY DT.datetime DESC';  
1950 - $aParams = array($this->documentid);  
1951 -  
1952 - $transactions = DBUtil::getResultArray(array($sQuery, $aParams));  
1953 - if (is_null($transactions) || PEAR::isError($transactions))  
1954 - {  
1955 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR);  
1956 - }  
1957 -  
1958 - return $transactions;  
1959 - } 51 + var $ktapi;
1960 52
1961 - /**  
1962 - * This returns the version history on the document.  
1963 - *  
1964 - * @return array  
1965 - */  
1966 - function get_version_history()  
1967 - {  
1968 - $metadata_versions = KTDocumentMetadataVersion::getByDocument($this->document);  
1969 -  
1970 - $versions = array();  
1971 - foreach ($metadata_versions as $version)  
1972 - {  
1973 - $document = &Document::get($this->documentid, $version->getId());  
1974 -  
1975 - $version = array();  
1976 -  
1977 - $userid = $document->getModifiedUserId();  
1978 - $user = User::get($userid);  
1979 -  
1980 - $version['user'] = $user->getName();  
1981 - $version['metadata_version'] = $document->getMetadataVersion();  
1982 - $version['content_version'] = $document->getVersion();  
1983 -  
1984 - $versions[] = $version;  
1985 - }  
1986 - return $versions; 53 + function &can_user_access_object_requiring_permission(&$object, $permission)
  54 + {
  55 + return $this->ktapi->can_user_access_object_requiring_permission($object, $permission);
1987 } 56 }
  57 +}
1988 58
1989 - /**  
1990 - * This expunges a document from the system.  
1991 - *  
1992 - * @access public  
1993 - */  
1994 - function expunge() 59 +class KTAPI_Error extends PEAR_Error
  60 +{
  61 + function KTAPI_Error($msg, $obj)
1995 { 62 {
1996 - if ($this->document->getStatusID() != 3) 63 + if (PEAR::isError($obj))
1997 { 64 {
1998 - return new PEAR_Error('You should not purge this'); 65 + parent::PEAR_Error($msg . ' - ' . $obj->getMessage());
1999 } 66 }
2000 - DBUtil::startTransaction();  
2001 -  
2002 - $transaction = & new DocumentTransaction($this->document, "Document expunged", 'ktcore.transactions.expunge');  
2003 -  
2004 - $transaction->create();  
2005 -  
2006 - $this->document->delete();  
2007 -  
2008 - $this->document->cleanupDocumentData($this->documentid);  
2009 -  
2010 - $storage =& KTStorageManagerUtil::getSingleton();  
2011 -  
2012 - $result= $storage->expunge($this->document);  
2013 -  
2014 - DBUtil::commit();  
2015 - }  
2016 -  
2017 - /**  
2018 - * This expunges a document from the system.  
2019 - *  
2020 - * @access public  
2021 - */  
2022 - function restore()  
2023 - {  
2024 - DBUtil::startTransaction();  
2025 -  
2026 - $storage =& KTStorageManagerUtil::getSingleton();  
2027 -  
2028 - $folder = Folder::get($this->document->getRestoreFolderId());  
2029 - if (PEAR::isError($folder))  
2030 - {  
2031 - $this->document->setFolderId(1);  
2032 - $folder = Folder::get(1);  
2033 - }  
2034 else 67 else
2035 { 68 {
2036 - $this->document->setFolderId($this->document->getRestoreFolderId()); 69 + parent::PEAR_Error($msg);
2037 } 70 }
2038 -  
2039 - $storage->restore($this->document);  
2040 -  
2041 - $this->document->setStatusId(LIVE);  
2042 - $this->document->setPermissionObjectId($folder->getPermissionObjectId());  
2043 - $res = $this->document->update();  
2044 -  
2045 - $res = KTPermissionUtil::updatePermissionLookup($this->document);  
2046 -  
2047 - $user = $this->ktapi->get_user();  
2048 -  
2049 - $oTransaction = new DocumentTransaction($this->document, 'Restored from deleted state by ' . $user->getName(), 'ktcore.transactions.update');  
2050 - $oTransaction->create();  
2051 -  
2052 - DBUtil::commit();  
2053 } 71 }
2054 } 72 }
2055 73
@@ -2163,7 +181,7 @@ class KTAPI @@ -2163,7 +181,7 @@ class KTAPI
2163 return new PEAR_Error('A session is currently active.'); 181 return new PEAR_Error('A session is currently active.');
2164 } 182 }
2165 183
2166 - $session = &KTAPI_Session::get_active_session($this, $session, $ip); 184 + $session = &KTAPI_UserSession::get_active_session($this, $session, $ip);
2167 185
2168 if (is_null($session) || PEAR::isError($session)) 186 if (is_null($session) || PEAR::isError($session))
2169 { 187 {
@@ -2189,7 +207,7 @@ class KTAPI @@ -2189,7 +207,7 @@ class KTAPI
2189 return new PEAR_Error('A session is currently active.'); 207 return new PEAR_Error('A session is currently active.');
2190 } 208 }
2191 209
2192 - $session = &KTAPI_Session::start_session($this, $username, $password, $ip); 210 + $session = &KTAPI_UserSession::start_session($this, $username, $password, $ip);
2193 if (is_null($session)) 211 if (is_null($session))
2194 { 212 {
2195 return new PEAR_Error('Session is null.'); 213 return new PEAR_Error('Session is null.');
@@ -2203,6 +221,19 @@ class KTAPI @@ -2203,6 +221,19 @@ class KTAPI
2203 return $session; 221 return $session;
2204 } 222 }
2205 223
  224 +
  225 + function & start_system_session()
  226 + {
  227 + $user = User::get(1);
  228 +
  229 + $session = & new KTAPI_SystemSession($this, $user);
  230 + $this->session = &$session;
  231 +
  232 + return $session;
  233 + }
  234 +
  235 +
  236 +
2206 /** 237 /**
2207 * Starts an anonymous session. 238 * Starts an anonymous session.
2208 * 239 *
@@ -2211,7 +242,23 @@ class KTAPI @@ -2211,7 +242,23 @@ class KTAPI
2211 */ 242 */
2212 function &start_anonymous_session($ip=null) 243 function &start_anonymous_session($ip=null)
2213 { 244 {
2214 - return $this->start_session('anonymous','',$ip); 245 + if (!is_null($this->session))
  246 + {
  247 + return new PEAR_Error('A session is currently active.');
  248 + }
  249 +
  250 + $session = &KTAPI_AnonymousSession::start_session($this, $ip);
  251 + if (is_null($session))
  252 + {
  253 + return new PEAR_Error('Session is null.');
  254 + }
  255 + if (PEAR::isError($session))
  256 + {
  257 + return new PEAR_Error('Session is invalid. ' . $session->getMessage());
  258 + }
  259 + $this->session = &$session;
  260 +
  261 + return $session;
2215 } 262 }
2216 263
2217 264
@@ -2288,7 +335,7 @@ class KTAPI @@ -2288,7 +335,7 @@ class KTAPI
2288 $rows = DBUtil::getResultArray($sql); 335 $rows = DBUtil::getResultArray($sql);
2289 if (is_null($rows) || PEAR::isError($rows)) 336 if (is_null($rows) || PEAR::isError($rows))
2290 { 337 {
2291 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR); 338 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $rows);
2292 } 339 }
2293 340
2294 $result = array(); 341 $result = array();
@@ -2313,7 +360,7 @@ class KTAPI @@ -2313,7 +360,7 @@ class KTAPI
2313 $rows = DBUtil::getResultArray($sql); 360 $rows = DBUtil::getResultArray($sql);
2314 if (is_null($rows) || PEAR::isError($rows)) 361 if (is_null($rows) || PEAR::isError($rows))
2315 { 362 {
2316 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR); 363 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $rows);
2317 } 364 }
2318 return $rows; 365 return $rows;
2319 } 366 }
@@ -2332,7 +379,7 @@ class KTAPI @@ -2332,7 +379,7 @@ class KTAPI
2332 $rows = DBUtil::getResultArray($sql); 379 $rows = DBUtil::getResultArray($sql);
2333 if (is_null($rows) || PEAR::isError($rows)) 380 if (is_null($rows) || PEAR::isError($rows))
2334 { 381 {
2335 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR); 382 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $rows);
2336 } 383 }
2337 $results=array(); 384 $results=array();
2338 foreach($rows as $row) 385 foreach($rows as $row)
@@ -2398,7 +445,7 @@ class KTAPI @@ -2398,7 +445,7 @@ class KTAPI
2398 $rows=DBUtil::getResultArray($sql); 445 $rows=DBUtil::getResultArray($sql);
2399 if (is_null($rows) || PEAR::isError($rows)) 446 if (is_null($rows) || PEAR::isError($rows))
2400 { 447 {
2401 - return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR); 448 + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $rows);
2402 } 449 }
2403 $results=array(); 450 $results=array();
2404 foreach($rows as $row) 451 foreach($rows as $row)
lib/documentmanagement/Document.inc
@@ -230,7 +230,11 @@ class Document { @@ -230,7 +230,11 @@ class Document {
230 $this->_oDocumentMetadataVersion = KTDocumentMetadataVersion::get($iMetadataVersionId); 230 $this->_oDocumentMetadataVersion = KTDocumentMetadataVersion::get($iMetadataVersionId);
231 $this->iCurrentMetadataVersionId = $iMetadataVersionId; 231 $this->iCurrentMetadataVersionId = $iMetadataVersionId;
232 } 232 }
233 - if (PEAR::isError($this->_oDocumentMetadataVersion)) { var_dump($this->_oDocumentMetadataVersion); return $this->_oDocumentMetadataVersion; } 233 + if (PEAR::isError($this->_oDocumentMetadataVersion))
  234 + {
  235 + // var_dump($this->_oDocumentMetadataVersion);
  236 + return $this->_oDocumentMetadataVersion;
  237 + }
234 238
235 $this->_oDocumentContentVersion = KTDocumentContentVersion::get($this->_oDocumentMetadataVersion->getContentVersionId()); 239 $this->_oDocumentContentVersion = KTDocumentContentVersion::get($this->_oDocumentMetadataVersion->getContentVersionId());
236 if (PEAR::isError($this->_oDocumentContentVersion)) { return $this->_oDocumentContentVersion; } 240 if (PEAR::isError($this->_oDocumentContentVersion)) { return $this->_oDocumentContentVersion; }
lib/foldermanagement/folderutil.inc.php
@@ -68,15 +68,19 @@ class KTFolderUtil { @@ -68,15 +68,19 @@ class KTFolderUtil {
68 } 68 }
69 69
70 function add ($oParentFolder, $sFolderName, $oUser) { 70 function add ($oParentFolder, $sFolderName, $oUser) {
71 - $oFolder = KTFolderUtil::_add($oParentFolder, $sFolderName, $oUser); 71 +
  72 +
  73 + $folderid=$oParentFolder->getId();
  74 + // check for conflicts first
  75 + if (Folder::folderExistsName($sFolderName,$folderid)) {
  76 + return PEAR::raiseError(sprintf(_kt('The folder %s already exists.'), $sFolderName));
  77 + }
  78 +
  79 + $oFolder = KTFolderUtil::_add($oParentFolder, $sFolderName, $oUser);
72 if (PEAR::isError($oFolder)) { 80 if (PEAR::isError($oFolder)) {
73 return $oFolder; 81 return $oFolder;
74 } 82 }
75 83
76 - // check for conflicts first  
77 - if (Folder::folderExistsName(KTUtil::getId($oParentFolder), $sFolderName)) {  
78 - return PEAR::raiseError(sprintf(_kt('The folder %s already exists.'), $sFolderName));  
79 - }  
80 84
81 $oTransaction = KTFolderTransaction::createFromArray(array( 85 $oTransaction = KTFolderTransaction::createFromArray(array(
82 'folderid' => $oFolder->getId(), 86 'folderid' => $oFolder->getId(),
lib/templating/kt3template.inc.php
@@ -39,6 +39,7 @@ @@ -39,6 +39,7 @@
39 * 39 *
40 */ 40 */
41 41
  42 +require_once(KT_LIB_DIR . "/plugins/pluginregistry.inc.php");
42 require_once(KT_LIB_DIR . "/templating/templating.inc.php"); 43 require_once(KT_LIB_DIR . "/templating/templating.inc.php");
43 require_once(KT_LIB_DIR . "/session/control.inc"); 44 require_once(KT_LIB_DIR . "/session/control.inc");
44 45
tests/runtests.php
@@ -5,6 +5,9 @@ require_once(&#39;test.php&#39;); @@ -5,6 +5,9 @@ require_once(&#39;test.php&#39;);
5 class UnitTests extends GroupTest { 5 class UnitTests extends GroupTest {
6 function UnitTests() { 6 function UnitTests() {
7 $this->GroupTest('Unit tests'); 7 $this->GroupTest('Unit tests');
  8 + $this->addTestFile('api/authentication.php');
  9 + $this->addTestFile('api/document.php');
  10 + $this->addTestFile('api/folder.php');
8 $this->addTestFile('SQLFile/test_sqlfile.php'); 11 $this->addTestFile('SQLFile/test_sqlfile.php');
9 $this->addTestFile('cache/testCache.php'); 12 $this->addTestFile('cache/testCache.php');
10 $this->addTestFile('config/testConfig.php'); 13 $this->addTestFile('config/testConfig.php');
@@ -29,3 +32,4 @@ if (SimpleReporter::inCli()) { @@ -29,3 +32,4 @@ if (SimpleReporter::inCli()) {
29 } 32 }
30 $test->run(new HtmlReporter()); 33 $test->run(new HtmlReporter());
31 34
  35 +?>
32 \ No newline at end of file 36 \ No newline at end of file
thirdparty/simpletest/simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE
@@ -5,6 +5,28 @@ written with earlier versions will fail with the newest ones. The most @@ -5,6 +5,28 @@ written with earlier versions will fail with the newest ones. The most
5 dramatic changes are in the alpha releases. Here is a list of possible 5 dramatic changes are in the alpha releases. Here is a list of possible
6 problems and their fixes... 6 problems and their fixes...
7 7
  8 +No method _getTest() on mocks
  9 +-----------------------------
  10 +This has finally been removed. It was a pretty esoteric
  11 +flex point anyway. It was there to allow the mocks to
  12 +work with other test tools, but no one does this anyway.
  13 +
  14 +No method assertError(), assertNoErrors(), swallowErrors()
  15 +----------------------------------------------------------
  16 +These have been deprecated in 1.0.1beta in favour of
  17 +expectError() and expectException(). assertNoErrors() is
  18 +redundant if you use expectError() as failures are now reporterted
  19 +immediately.
  20 +
  21 +No method TestCase::signal()
  22 +----------------------------
  23 +This has been deprecated in favour of triggering an error or
  24 +throwing an exception. Deprecated as of 1.0.1beta.
  25 +
  26 +No method TestCase::sendMessage()
  27 +---------------------------------
  28 +This has been deprecated as of 1.0.1beta.
  29 +
8 Failure to connect now emits failures 30 Failure to connect now emits failures
9 ------------------------------------- 31 -------------------------------------
10 It used to be that you would have to use the 32 It used to be that you would have to use the
@@ -46,7 +68,7 @@ No method addPartialMockCode() @@ -46,7 +68,7 @@ No method addPartialMockCode()
46 ------------------------------ 68 ------------------------------
47 The ability to insert arbitrary partial mock code 69 The ability to insert arbitrary partial mock code
48 has been removed. This was a low value feature 70 has been removed. This was a low value feature
49 -causing needless complications.It was removed 71 +causing needless complications. It was removed
50 in the 1.0.1beta release. 72 in the 1.0.1beta release.
51 73
52 No method setMockBaseClass() 74 No method setMockBaseClass()
@@ -139,7 +161,7 @@ My custom test case ignored by tally() @@ -139,7 +161,7 @@ My custom test case ignored by tally()
139 The _assertTrue method has had it's signature changed due to a bug 161 The _assertTrue method has had it's signature changed due to a bug
140 in the PHP 5.0.1 release. You must now use getTest() from within 162 in the PHP 5.0.1 release. You must now use getTest() from within
141 that method to get the test case. Mock compatibility with other 163 that method to get the test case. Mock compatibility with other
142 -unit testers is now deprecated as of 1.0.1alpha as PEAR::PHUnit2 164 +unit testers is now deprecated as of 1.0.1alpha as PEAR::PHPUnit2
143 should soon have mock support of it's own. 165 should soon have mock support of it's own.
144 166
145 Broken code extending SimpleRunner 167 Broken code extending SimpleRunner
thirdparty/simpletest/simpletest/LICENSE
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 Version 2.1, February 1999 2 Version 2.1, February 1999
3 3
4 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 4 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5 - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 5 + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies 6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed. 7 of this license document, but changing it is not allowed.
8 8
@@ -485,7 +485,7 @@ convey the exclusion of warranty; and each file should have at least the @@ -485,7 +485,7 @@ convey the exclusion of warranty; and each file should have at least the
485 485
486 You should have received a copy of the GNU Lesser General Public 486 You should have received a copy of the GNU Lesser General Public
487 License along with this library; if not, write to the Free Software 487 License along with this library; if not, write to the Free Software
488 - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 488 + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
489 489
490 Also add information on how to contact you by electronic and paper mail. 490 Also add information on how to contact you by electronic and paper mail.
491 491
thirdparty/simpletest/simpletest/README
1 SimpleTest 1 SimpleTest
2 ========== 2 ==========
3 You probably got this package from... 3 You probably got this package from...
4 -http://sourceforge.net/projects/simpletest/ 4 +http://simpletest.sourceforge.net/projects/simpletest/
5 5
6 If there is no licence agreement with this package please download 6 If there is no licence agreement with this package please download
7 a version from the location above. You must read and accept that 7 a version from the location above. You must read and accept that
thirdparty/simpletest/simpletest/VERSION
1 -1.0.1alpha3  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +1.0.1beta
3 \ No newline at end of file 3 \ No newline at end of file
thirdparty/simpletest/simpletest/browser.php
@@ -894,6 +894,17 @@ @@ -894,6 +894,17 @@
894 $form->submitButton(new SimpleById($id), $additional)); 894 $form->submitButton(new SimpleById($id), $additional));
895 return ($success ? $this->getContent() : $success); 895 return ($success ? $this->getContent() : $success);
896 } 896 }
  897 +
  898 + /**
  899 + * Tests to see if a submit button exists with this
  900 + * label.
  901 + * @param string $label Button label.
  902 + * @return boolean True if present.
  903 + * @access public
  904 + */
  905 + function isSubmit($label) {
  906 + return (boolean)$this->_page->getFormBySubmit(new SimpleByLabel($label));
  907 + }
897 908
898 /** 909 /**
899 * Clicks the submit image by some kind of label. Usually 910 * Clicks the submit image by some kind of label. Usually
@@ -962,6 +973,17 @@ @@ -962,6 +973,17 @@
962 $form->submitImage(new SimpleById($id), $x, $y, $additional)); 973 $form->submitImage(new SimpleById($id), $x, $y, $additional));
963 return ($success ? $this->getContent() : $success); 974 return ($success ? $this->getContent() : $success);
964 } 975 }
  976 +
  977 + /**
  978 + * Tests to see if an image exists with this
  979 + * title or alt text.
  980 + * @param string $label Image text.
  981 + * @return boolean True if present.
  982 + * @access public
  983 + */
  984 + function isImage($label) {
  985 + return (boolean)$this->_page->getFormByImage(new SimpleByLabel($label));
  986 + }
965 987
966 /** 988 /**
967 * Submits a form by the ID. 989 * Submits a form by the ID.
@@ -981,16 +1003,16 @@ @@ -981,16 +1003,16 @@
981 } 1003 }
982 1004
983 /** 1005 /**
984 - * Follows a link by label. Will click the first link 1006 + * Finds a URL by label. Will find the first link
985 * found with this link text by default, or a later 1007 * found with this link text by default, or a later
986 * one if an index is given. The match ignores case and 1008 * one if an index is given. The match ignores case and
987 * white space issues. 1009 * white space issues.
988 * @param string $label Text between the anchor tags. 1010 * @param string $label Text between the anchor tags.
989 * @param integer $index Link position counting from zero. 1011 * @param integer $index Link position counting from zero.
990 - * @return string/boolean Page on success. 1012 + * @return string/boolean URL on success.
991 * @access public 1013 * @access public
992 */ 1014 */
993 - function clickLink($label, $index = 0) { 1015 + function getLink($label, $index = 0) {
994 $urls = $this->_page->getUrlsByLabel($label); 1016 $urls = $this->_page->getUrlsByLabel($label);
995 if (count($urls) == 0) { 1017 if (count($urls) == 0) {
996 return false; 1018 return false;
@@ -998,18 +1020,36 @@ @@ -998,18 +1020,36 @@
998 if (count($urls) < $index + 1) { 1020 if (count($urls) < $index + 1) {
999 return false; 1021 return false;
1000 } 1022 }
1001 - $this->_load($urls[$index], new SimpleGetEncoding());  
1002 - return $this->getContent(); 1023 + return $urls[$index];
1003 } 1024 }
1004 1025
1005 /** 1026 /**
1006 - * Tests to see if a link is present by label.  
1007 - * @param string $label Text of value attribute.  
1008 - * @return boolean True if link present. 1027 + * Follows a link by label. Will click the first link
  1028 + * found with this link text by default, or a later
  1029 + * one if an index is given. The match ignores case and
  1030 + * white space issues.
  1031 + * @param string $label Text between the anchor tags.
  1032 + * @param integer $index Link position counting from zero.
  1033 + * @return string/boolean Page on success.
  1034 + * @access public
  1035 + */
  1036 + function clickLink($label, $index = 0) {
  1037 + $url = $this->getLink($label, $index);
  1038 + if ($url === false) {
  1039 + return false;
  1040 + }
  1041 + $this->_load($url, new SimpleGetEncoding());
  1042 + return $this->getContent();
  1043 + }
  1044 +
  1045 + /**
  1046 + * Finds a link by id attribute.
  1047 + * @param string $id ID attribute value.
  1048 + * @return string/boolean URL on success.
1009 * @access public 1049 * @access public
1010 */ 1050 */
1011 - function isLink($label) {  
1012 - return (count($this->_page->getUrlsByLabel($label)) > 0); 1051 + function getLinkById($id) {
  1052 + return $this->_page->getUrlById($id);
1013 } 1053 }
1014 1054
1015 /** 1055 /**
@@ -1019,7 +1059,7 @@ @@ -1019,7 +1059,7 @@
1019 * @access public 1059 * @access public
1020 */ 1060 */
1021 function clickLinkById($id) { 1061 function clickLinkById($id) {
1022 - if (! ($url = $this->_page->getUrlById($id))) { 1062 + if (! ($url = $this->getLinkById($id))) {
1023 return false; 1063 return false;
1024 } 1064 }
1025 $this->_load($url, new SimpleGetEncoding()); 1065 $this->_load($url, new SimpleGetEncoding());
@@ -1027,16 +1067,6 @@ @@ -1027,16 +1067,6 @@
1027 } 1067 }
1028 1068
1029 /** 1069 /**
1030 - * Tests to see if a link is present by ID attribute.  
1031 - * @param string $id Text of id attribute.  
1032 - * @return boolean True if link present.  
1033 - * @access public  
1034 - */  
1035 - function isLinkById($id) {  
1036 - return (boolean)$this->_page->getUrlById($id);  
1037 - }  
1038 -  
1039 - /**  
1040 * Clicks a visible text item. Will first try buttons, 1070 * Clicks a visible text item. Will first try buttons,
1041 * then links and then images. 1071 * then links and then images.
1042 * @param string $label Visible text or alt text. 1072 * @param string $label Visible text or alt text.
@@ -1053,5 +1083,15 @@ @@ -1053,5 +1083,15 @@
1053 } 1083 }
1054 return $raw; 1084 return $raw;
1055 } 1085 }
  1086 +
  1087 + /**
  1088 + * Tests to see if a click target exists.
  1089 + * @param string $label Visible text or alt text.
  1090 + * @return boolean True if target present.
  1091 + * @access public
  1092 + */
  1093 + function isClickable($label) {
  1094 + return $this->isSubmit($label) || ($this->getLink($label) !== false) || $this->isImage($label);
  1095 + }
1056 } 1096 }
1057 ?> 1097 ?>
1058 \ No newline at end of file 1098 \ No newline at end of file
thirdparty/simpletest/simpletest/collector.php
1 <?php 1 <?php
2 -/**  
3 - * This file contains the following classes: {@link SimpleCollector},  
4 - * {@link SimplePatternCollector}.  
5 - *  
6 - * @author Travis Swicegood <development@domain51.com>  
7 - * @package SimpleTest  
8 - * @subpackage UnitTester  
9 - * @version $Id$  
10 - */  
11 -  
12 -/**  
13 - * The basic collector for {@link GroupTest}  
14 - *  
15 - * @see collect(), GroupTest::collect()  
16 - * @package SimpleTest  
17 - * @subpackage UnitTester  
18 - */  
19 -class SimpleCollector {  
20 -  
21 /** 2 /**
22 - * Strips off any kind of slash at the end so as to normalise the path 3 + * This file contains the following classes: {@link SimpleCollector},
  4 + * {@link SimplePatternCollector}.
23 * 5 *
24 - * @param string $path Path to normalise. 6 + * @author Travis Swicegood <development@domain51.com>
  7 + * @package SimpleTest
  8 + * @subpackage UnitTester
  9 + * @version $Id$
25 */ 10 */
26 - function _removeTrailingSlash($path) {  
27 - return preg_replace('|[\\/]$|', '', $path);  
28 -  
29 - /**  
30 - * @internal  
31 - * Try benchmarking the following. It's more code, but by not using the  
32 - * regex, it may be faster? Also, shouldn't be looking for  
33 - * DIRECTORY_SEPERATOR instead of a manual "/"?  
34 - */  
35 - if (substr($path, -1) == DIRECTORY_SEPERATOR) {  
36 - return substr($path, 0, -1);  
37 - } else {  
38 - return $path;  
39 - }  
40 - }  
41 - 11 +
42 /** 12 /**
43 - * Scans the directory and adds what it can.  
44 - * @param object $test Group test with {@link GroupTest::addTestFile()} method.  
45 - * @param string $path Directory to scan.  
46 - * @see _attemptToAdd() 13 + * The basic collector for {@link GroupTest}
  14 + *
  15 + * @see collect(), GroupTest::collect()
  16 + * @package SimpleTest
  17 + * @subpackage UnitTester
47 */ 18 */
48 - function collect(&$test, $path) {  
49 - $path = $this->_removeTrailingSlash($path);  
50 - if ($handle = opendir($path)) {  
51 - while (($entry = readdir($handle)) !== false) {  
52 - $this->_handle($test, $path . DIRECTORY_SEPARATOR . $entry); 19 + class SimpleCollector {
  20 +
  21 + /**
  22 + * Strips off any kind of slash at the end so as to normalise the path.
  23 + * @param string $path Path to normalise.
  24 + * @return string Path without trailing slash.
  25 + */
  26 + function _removeTrailingSlash($path) {
  27 + if (substr($path, -1) == DIRECTORY_SEPARATOR) {
  28 + return substr($path, 0, -1);
  29 + } elseif (substr($path, -1) == '/') {
  30 + return substr($path, 0, -1);
  31 + } else {
  32 + return $path;
53 } 33 }
54 - closedir($handle);  
55 } 34 }
56 - }  
57 35
58 - /**  
59 - * This method determines what should be done with a given file and adds  
60 - * it via {@link GroupTest::addTestFile()} if necessary.  
61 - *  
62 - * This method should be overriden to provide custom matching criteria,  
63 - * such as pattern matching, recursive matching, etc. For an example, see  
64 - * {@link SimplePatternCollector::_handle()}.  
65 - *  
66 - * @param object $test Group test with {@link GroupTest::addTestFile()} method.  
67 - * @param string $filename A filename as generated by {@link collect()}  
68 - * @see collect()  
69 - * @access protected  
70 - */  
71 - function _handle(&$test, $file) {  
72 - if (!is_dir($file)) {  
73 - $test->addTestFile($file); 36 + /**
  37 + * Scans the directory and adds what it can.
  38 + * @param object $test Group test with {@link GroupTest::addTestFile()} method.
  39 + * @param string $path Directory to scan.
  40 + * @see _attemptToAdd()
  41 + */
  42 + function collect(&$test, $path) {
  43 + $path = $this->_removeTrailingSlash($path);
  44 + if ($handle = opendir($path)) {
  45 + while (($entry = readdir($handle)) !== false) {
  46 + $this->_handle($test, $path . DIRECTORY_SEPARATOR . $entry);
  47 + }
  48 + closedir($handle);
  49 + }
74 } 50 }
75 - }  
76 -}  
77 -  
78 -/**  
79 - * An extension to {@link SimpleCollector} that only adds files matching a  
80 - * given pattern.  
81 - *  
82 - * @package SimpleTest  
83 - * @subpackage UnitTester  
84 - * @see SimpleCollector  
85 - */  
86 -class SimplePatternCollector extends SimpleCollector {  
87 - var $_pattern;  
88 51
  52 + /**
  53 + * This method determines what should be done with a given file and adds
  54 + * it via {@link GroupTest::addTestFile()} if necessary.
  55 + *
  56 + * This method should be overriden to provide custom matching criteria,
  57 + * such as pattern matching, recursive matching, etc. For an example, see
  58 + * {@link SimplePatternCollector::_handle()}.
  59 + *
  60 + * @param object $test Group test with {@link GroupTest::addTestFile()} method.
  61 + * @param string $filename A filename as generated by {@link collect()}
  62 + * @see collect()
  63 + * @access protected
  64 + */
  65 + function _handle(&$test, $file) {
  66 + if (! is_dir($file)) {
  67 + $test->addTestFile($file);
  68 + }
  69 + }
  70 + }
89 71
90 /** 72 /**
  73 + * An extension to {@link SimpleCollector} that only adds files matching a
  74 + * given pattern.
91 * 75 *
92 - * @param string $pattern Perl compatible regex to test name against  
93 - * See {@link http://us4.php.net/manual/en/reference.pcre.pattern.syntax.php PHP's PCRE}  
94 - * for full documentation of valid pattern.s 76 + * @package SimpleTest
  77 + * @subpackage UnitTester
  78 + * @see SimpleCollector
95 */ 79 */
96 - function SimplePatternCollector($pattern = '/php$/i') {  
97 - $this->_pattern = $pattern;  
98 - } 80 + class SimplePatternCollector extends SimpleCollector {
  81 + var $_pattern;
99 82
  83 + /**
  84 + *
  85 + * @param string $pattern Perl compatible regex to test name against
  86 + * See {@link http://us4.php.net/manual/en/reference.pcre.pattern.syntax.php PHP's PCRE}
  87 + * for full documentation of valid pattern.s
  88 + */
  89 + function SimplePatternCollector($pattern = '/php$/i') {
  90 + $this->_pattern = $pattern;
  91 + }
100 92
101 - /**  
102 - * Attempts to add files that match a given pattern.  
103 - *  
104 - * @see SimpleCollector::_handle()  
105 - * @param object $test Group test with {@link GroupTest::addTestFile()} method.  
106 - * @param string $path Directory to scan.  
107 - * @access protected  
108 - */  
109 - function _handle(&$test, $filename) {  
110 - if (preg_match($this->_pattern, $filename)) {  
111 - parent::_handle($test, $filename); 93 + /**
  94 + * Attempts to add files that match a given pattern.
  95 + *
  96 + * @see SimpleCollector::_handle()
  97 + * @param object $test Group test with {@link GroupTest::addTestFile()} method.
  98 + * @param string $path Directory to scan.
  99 + * @access protected
  100 + */
  101 + function _handle(&$test, $filename) {
  102 + if (preg_match($this->_pattern, $filename)) {
  103 + parent::_handle($test, $filename);
  104 + }
112 } 105 }
113 } 106 }
114 -}  
115 ?> 107 ?>
116 \ No newline at end of file 108 \ No newline at end of file
thirdparty/simpletest/simpletest/compatibility.php
@@ -70,6 +70,9 @@ @@ -70,6 +70,9 @@
70 if (is_array($first) && is_array($second)) { 70 if (is_array($first) && is_array($second)) {
71 return SimpleTestCompatibility::_isArrayOfIdenticalTypes($first, $second); 71 return SimpleTestCompatibility::_isArrayOfIdenticalTypes($first, $second);
72 } 72 }
  73 + if ($first !== $second) {
  74 + return false;
  75 + }
73 return true; 76 return true;
74 } 77 }
75 78
@@ -105,8 +108,7 @@ @@ -105,8 +108,7 @@
105 * @static 108 * @static
106 */ 109 */
107 function isReference(&$first, &$second) { 110 function isReference(&$first, &$second) {
108 - if (version_compare(phpversion(), '5', '>=')  
109 - && is_object($first)) { 111 + if (version_compare(phpversion(), '5', '>=') && is_object($first)) {
110 return ($first === $second); 112 return ($first === $second);
111 } 113 }
112 if (is_object($first) && is_object($second)) { 114 if (is_object($first) && is_object($second)) {
@@ -133,9 +135,6 @@ @@ -133,9 +135,6 @@
133 * @static 135 * @static
134 */ 136 */
135 function isA($object, $class) { 137 function isA($object, $class) {
136 - if (function_exists('is_a')) {  
137 - return is_a($object, $class);  
138 - }  
139 if (version_compare(phpversion(), '5') >= 0) { 138 if (version_compare(phpversion(), '5') >= 0) {
140 if (! class_exists($class, false)) { 139 if (! class_exists($class, false)) {
141 if (function_exists('interface_exists')) { 140 if (function_exists('interface_exists')) {
@@ -147,6 +146,9 @@ @@ -147,6 +146,9 @@
147 eval("\$is_a = \$object instanceof $class;"); 146 eval("\$is_a = \$object instanceof $class;");
148 return $is_a; 147 return $is_a;
149 } 148 }
  149 + if (function_exists('is_a')) {
  150 + return is_a($object, $class);
  151 + }
150 return ((strtolower($class) == get_class($object)) 152 return ((strtolower($class) == get_class($object))
151 or (is_subclass_of($object, $class))); 153 or (is_subclass_of($object, $class)));
152 } 154 }
@@ -167,18 +169,5 @@ @@ -167,18 +169,5 @@
167 set_socket_timeout($handle, $timeout, 0); 169 set_socket_timeout($handle, $timeout, 0);
168 } 170 }
169 } 171 }
170 -  
171 - /**  
172 - * Gets the current stack trace topmost first.  
173 - * @return array List of stack frames.  
174 - * @access public  
175 - * @static  
176 - */  
177 - function getStackTrace() {  
178 - if (function_exists('debug_backtrace')) {  
179 - return array_reverse(debug_backtrace());  
180 - }  
181 - return array();  
182 - }  
183 } 172 }
184 -?> 173 -?>
  174 +?>
185 \ No newline at end of file 175 \ No newline at end of file
thirdparty/simpletest/simpletest/dumper.php
@@ -356,47 +356,5 @@ @@ -356,47 +356,5 @@
356 ob_end_clean(); 356 ob_end_clean();
357 return $formatted; 357 return $formatted;
358 } 358 }
359 -  
360 - /**  
361 - * Extracts the last assertion that was not within  
362 - * Simpletest itself. The name must start with "assert".  
363 - * @param array $stack List of stack frames.  
364 - * @access public  
365 - * @static  
366 - */  
367 - function getFormattedAssertionLine($stack) {  
368 - foreach ($stack as $frame) {  
369 - if (isset($frame['file'])) {  
370 - if (strpos($frame['file'], SIMPLE_TEST) !== false) {  
371 - if (dirname($frame['file']) . '/' == SIMPLE_TEST) {  
372 - continue;  
373 - }  
374 - }  
375 - }  
376 - if (SimpleDumper::_stackFrameIsAnAssertion($frame)) {  
377 - return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ']';  
378 - }  
379 - }  
380 - return '';  
381 - }  
382 -  
383 - /**  
384 - * Tries to determine if the method call is an assertion.  
385 - * @param array $frame PHP stack frame.  
386 - * @access private  
387 - * @static  
388 - */  
389 - function _stackFrameIsAnAssertion($frame) {  
390 - if (($frame['function'] == 'fail') || ($frame['function'] == 'pass')) {  
391 - return true;  
392 - }  
393 - if (strncmp($frame['function'], 'assert', 6) == 0) {  
394 - return true;  
395 - }  
396 - if (strncmp($frame['function'], 'expect', 6) == 0) {  
397 - return true;  
398 - }  
399 - return false;  
400 - }  
401 } 359 }
402 ?> 360 ?>
403 \ No newline at end of file 361 \ No newline at end of file
thirdparty/simpletest/simpletest/encoding.php
@@ -37,7 +37,7 @@ @@ -37,7 +37,7 @@
37 * @access public 37 * @access public
38 */ 38 */
39 function asRequest() { 39 function asRequest() {
40 - return $this->_key . '=' . urlencode($this->_value); 40 + return urlencode($this->_key) . '=' . urlencode($this->_value);
41 } 41 }
42 42
43 /** 43 /**
thirdparty/simpletest/simpletest/errors.php
@@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
15 * Includes SimpleTest files. 15 * Includes SimpleTest files.
16 */ 16 */
17 require_once(dirname(__FILE__) . '/invoker.php'); 17 require_once(dirname(__FILE__) . '/invoker.php');
  18 + require_once(dirname(__FILE__) . '/test_case.php');
  19 + require_once(dirname(__FILE__) . '/expectation.php');
18 20
19 /** 21 /**
20 * Extension that traps errors into an error queue. 22 * Extension that traps errors into an error queue.
@@ -39,13 +41,15 @@ @@ -39,13 +41,15 @@
39 * @access public 41 * @access public
40 */ 42 */
41 function invoke($method) { 43 function invoke($method) {
42 - set_error_handler('simpleTestErrorHandler'); 44 + $context = &SimpleTest::getContext();
  45 + $queue = &$context->get('SimpleErrorQueue');
  46 + $queue->setTestCase($this->GetTestCase());
  47 + set_error_handler('SimpleTestErrorHandler');
43 parent::invoke($method); 48 parent::invoke($method);
44 - $queue = &SimpleErrorQueue::instance();  
45 - while (list($severity, $message, $file, $line, $globals) = $queue->extract()) { 49 + while (list($severity, $message, $file, $line) = $queue->extract()) {
46 $severity = SimpleErrorQueue::getSeverityAsString($severity); 50 $severity = SimpleErrorQueue::getSeverityAsString($severity);
47 - $test_case = &$this->getTestCase();  
48 - $test_case->error($severity, $message, $file, $line); 51 + $test = &$this->getTestCase();
  52 + $test->error($severity, $message, $file, $line);
49 } 53 }
50 restore_error_handler(); 54 restore_error_handler();
51 } 55 }
@@ -59,28 +63,63 @@ @@ -59,28 +63,63 @@
59 */ 63 */
60 class SimpleErrorQueue { 64 class SimpleErrorQueue {
61 var $_queue; 65 var $_queue;
  66 + var $_expectation_queue;
  67 + var $_test;
62 68
63 /** 69 /**
64 * Starts with an empty queue. 70 * Starts with an empty queue.
65 - * @access public  
66 */ 71 */
67 function SimpleErrorQueue() { 72 function SimpleErrorQueue() {
68 $this->clear(); 73 $this->clear();
69 } 74 }
70 75
71 /** 76 /**
  77 + * Sets the currently running test case.
  78 + * @param SimpleTestCase $test Test case to send messages to.
  79 + * @access public
  80 + */
  81 + function setTestCase(&$test) {
  82 + $this->_test = &$test;
  83 + }
  84 +
  85 + /**
72 * Adds an error to the front of the queue. 86 * Adds an error to the front of the queue.
73 - * @param $severity PHP error code.  
74 - * @param $message Text of error.  
75 - * @param $filename File error occoured in.  
76 - * @param $line Line number of error.  
77 - * @param $super_globals Hash of PHP super global arrays. 87 + * @param integer $severity PHP error code.
  88 + * @param string $content Text of error.
  89 + * @param string $filename File error occoured in.
  90 + * @param integer $line Line number of error.
78 * @access public 91 * @access public
79 */ 92 */
80 - function add($severity, $message, $filename, $line, $super_globals) {  
81 - array_push(  
82 - $this->_queue,  
83 - array($severity, $message, $filename, $line, $super_globals)); 93 + function add($severity, $content, $filename, $line) {
  94 + $content = str_replace('%', '%%', $content);
  95 + if (count($this->_expectation_queue)) {
  96 + $this->_testLatestError($severity, $content, $filename, $line);
  97 + } else {
  98 + array_push(
  99 + $this->_queue,
  100 + array($severity, $content, $filename, $line));
  101 + }
  102 + }
  103 +
  104 + /**
  105 + * Tests the error against the most recent expected
  106 + * error.
  107 + * @param integer $severity PHP error code.
  108 + * @param string $content Text of error.
  109 + * @param string $filename File error occoured in.
  110 + * @param integer $line Line number of error.
  111 + * @access private
  112 + */
  113 + function _testLatestError($severity, $content, $filename, $line) {
  114 + list($expected, $message) = array_shift($this->_expectation_queue);
  115 + $severity = $this->getSeverityAsString($severity);
  116 + $is_match = $this->_test->assert(
  117 + $expected,
  118 + $content,
  119 + sprintf($message, "%s -> PHP error [$content] severity [$severity] in [$filename] line [$line]"));
  120 + if (! $is_match) {
  121 + $this->_test->error($severity, $content, $filename, $line);
  122 + }
84 } 123 }
85 124
86 /** 125 /**
@@ -105,32 +144,52 @@ @@ -105,32 +144,52 @@
105 */ 144 */
106 function clear() { 145 function clear() {
107 $this->_queue = array(); 146 $this->_queue = array();
  147 + $this->_expectation_queue = array();
108 } 148 }
109 149
110 /** 150 /**
111 - * Tests to see if the queue is empty.  
112 - * @return True if empty. 151 + * @deprecated
113 */ 152 */
114 - function isEmpty() {  
115 - return (count($this->_queue) == 0); 153 + function assertNoErrors($message) {
  154 + return $this->_test->assert(
  155 + new TrueExpectation(),
  156 + count($this->_queue) == 0,
  157 + sprintf($message, 'Should be no errors'));
116 } 158 }
117 159
118 /** 160 /**
119 - * Global access to a single error queue.  
120 - * @return Global error queue object.  
121 - * @access public  
122 - * @static 161 + * @deprecated
123 */ 162 */
124 - function &instance() {  
125 - static $queue = false;  
126 - if (! $queue) {  
127 - $queue = new SimpleErrorQueue(); 163 + function assertError($expected, $message) {
  164 + if (count($this->_queue) == 0) {
  165 + $this->_test->fail(sprintf($message, 'Expected error not found'));
  166 + return false;
128 } 167 }
129 - return $queue; 168 + list($severity, $content, $file, $line) = $this->extract();
  169 + $severity = $this->getSeverityAsString($severity);
  170 + return $this->_test->assert(
  171 + $expected,
  172 + $content,
  173 + sprintf($message, "Expected PHP error [$content] severity [$severity] in [$file] line [$line]"));
  174 + }
  175 +
  176 + /**
  177 + * Sets up an expectation of an error. If this is
  178 + * not fulfilled at the end of the test, a failure
  179 + * will occour. If the error does happen, then this
  180 + * will cancel it out and send a pass message.
  181 + * @param SimpleExpectation $expected Expected error match.
  182 + * @param string $message Message to display.
  183 + * @access public
  184 + */
  185 + function expectError($expected, $message) {
  186 + array_push(
  187 + $this->_expectation_queue,
  188 + array($expected, $message));
130 } 189 }
131 190
132 /** 191 /**
133 - * Converst an error code into it's string 192 + * Converts an error code into it's string
134 * representation. 193 * representation.
135 * @param $severity PHP integer error code. 194 * @param $severity PHP integer error code.
136 * @return String version of error code. 195 * @return String version of error code.
@@ -167,16 +226,17 @@ @@ -167,16 +226,17 @@
167 * @static 226 * @static
168 * @access public 227 * @access public
169 */ 228 */
170 - function simpleTestErrorHandler($severity, $message, $filename, $line, $super_globals) { 229 + function SimpleTestErrorHandler($severity, $message, $filename, $line, $super_globals) {
171 if ($severity = $severity & error_reporting()) { 230 if ($severity = $severity & error_reporting()) {
172 restore_error_handler(); 231 restore_error_handler();
173 if (ini_get('log_errors')) { 232 if (ini_get('log_errors')) {
174 $label = SimpleErrorQueue::getSeverityAsString($severity); 233 $label = SimpleErrorQueue::getSeverityAsString($severity);
175 error_log("$label: $message in $filename on line $line"); 234 error_log("$label: $message in $filename on line $line");
176 } 235 }
177 - $queue = &SimpleErrorQueue::instance();  
178 - $queue->add($severity, $message, $filename, $line, $super_globals);  
179 - set_error_handler('simpleTestErrorHandler'); 236 + $context = &SimpleTest::getContext();
  237 + $queue = &$context->get('SimpleErrorQueue');
  238 + $queue->add($severity, $message, $filename, $line);
  239 + set_error_handler('SimpleTestErrorHandler');
180 } 240 }
181 } 241 }
182 ?> 242 ?>
183 \ No newline at end of file 243 \ No newline at end of file
thirdparty/simpletest/simpletest/exceptions.php 0 → 100644
  1 +<?php
  2 + /**
  3 + * base include file for SimpleTest
  4 + * @package SimpleTest
  5 + * @subpackage UnitTester
  6 + * @version $Id: exceptions.php,v 1.12 2006/11/09 23:14:48 lastcraft Exp $
  7 + */
  8 +
  9 + /**#@+
  10 + * Includes SimpleTest files and defined the root constant
  11 + * for dependent libraries.
  12 + */
  13 + require_once(dirname(__FILE__) . '/invoker.php');
  14 + require_once(dirname(__FILE__) . '/expectation.php');
  15 +
  16 + /**
  17 + * Extension that traps exceptions and turns them into
  18 + * an error message. PHP5 only.
  19 + * @package SimpleTest
  20 + * @subpackage UnitTester
  21 + */
  22 + class SimpleExceptionTrappingInvoker extends SimpleInvokerDecorator {
  23 +
  24 + /**
  25 + * Stores the invoker to be wrapped.
  26 + * @param SimpleInvoker $invoker Test method runner.
  27 + */
  28 + function SimpleExceptionTrappingInvoker($invoker) {
  29 + $this->SimpleInvokerDecorator($invoker);
  30 + }
  31 +
  32 + /**
  33 + * Invokes a test method whilst trapping expected
  34 + * exceptions. Any left over unthrown exceptions
  35 + * are then reported as failures.
  36 + * @param string $method Test method to call.
  37 + */
  38 + function invoke($method) {
  39 + $trap = SimpleTest::getContext()->get('SimpleExceptionTrap');
  40 + $trap->clear();
  41 + try {
  42 + parent::invoke($method);
  43 + } catch (Exception $exception) {
  44 + if (! $trap->isExpected($this->getTestCase(), $exception)) {
  45 + $this->getTestCase()->exception($exception);
  46 + }
  47 + $trap->clear();
  48 + }
  49 + if ($message = $trap->getOutstanding()) {
  50 + $this->getTestCase()->fail($message);
  51 + }
  52 + }
  53 + }
  54 +
  55 + /**
  56 + * Tests exceptions either by type or the exact
  57 + * exception. This could be improved to accept
  58 + * a pattern expectation to test the error
  59 + * message, but that will have to come later.
  60 + * @package SimpleTest
  61 + * @subpackage UnitTester
  62 + */
  63 + class ExceptionExpectation extends SimpleExpectation {
  64 + private $expected;
  65 +
  66 + /**
  67 + * Sets up the conditions to test against.
  68 + * If the expected value is a string, then
  69 + * it will act as a test of the class name.
  70 + * An exception as the comparison will
  71 + * trigger an identical match. Writing this
  72 + * down now makes it look doubly dumb. I hope
  73 + * come up with a better scheme later.
  74 + * @param mixed $expected A class name or an actual
  75 + * exception to compare with.
  76 + * @param string $message Message to display.
  77 + */
  78 + function __construct($expected, $message = '%s') {
  79 + $this->expected = $expected;
  80 + parent::__construct($message);
  81 + }
  82 +
  83 + /**
  84 + * Carry out the test.
  85 + * @param Exception $compare Value to check.
  86 + * @return boolean True if matched.
  87 + */
  88 + function test($compare) {
  89 + if (is_string($this->expected)) {
  90 + return ($compare instanceof $this->expected);
  91 + }
  92 + if (get_class($compare) != get_class($this->expected)) {
  93 + return false;
  94 + }
  95 + return $compare->getMessage() == $this->expected->getMessage();
  96 + }
  97 +
  98 + /**
  99 + * Create the message to display describing the test.
  100 + * @param Exception $compare Exception to match.
  101 + * @return string Final message.
  102 + */
  103 + function testMessage($compare) {
  104 + if (is_string($this->expected)) {
  105 + return "Exception [" . $this->describeException($compare) .
  106 + "] should be type [" . $this->expected . "]";
  107 + }
  108 + return "Exception [" . $this->describeException($compare) .
  109 + "] should match [" .
  110 + $this->describeException($this->expected) . "]";
  111 + }
  112 +
  113 + /**
  114 + * Summary of an Exception object.
  115 + * @param Exception $compare Exception to describe.
  116 + * @return string Text description.
  117 + */
  118 + protected function describeException($exception) {
  119 + return get_class($exception) . ": " . $exception->getMessage();
  120 + }
  121 + }
  122 +
  123 + /**
  124 + * Stores expected exceptions for when they
  125 + * get thrown. Saves the irritating try...catch
  126 + * block.
  127 + * @package SimpleTest
  128 + * @subpackage UnitTester
  129 + */
  130 + class SimpleExceptionTrap {
  131 + private $expected;
  132 + private $message;
  133 +
  134 + /**
  135 + * Clears down the queue ready for action.
  136 + */
  137 + function __construct() {
  138 + $this->clear();
  139 + }
  140 +
  141 + /**
  142 + * Sets up an expectation of an exception.
  143 + * This has the effect of intercepting an
  144 + * exception that matches.
  145 + * @param SimpleExpectation $expected Expected exception to match.
  146 + * @param string $message Message to display.
  147 + * @access public
  148 + */
  149 + function expectException($expected = false, $message = '%s') {
  150 + if ($expected === false) {
  151 + $expected = new AnythingExpectation();
  152 + }
  153 + if (! SimpleExpectation::isExpectation($expected)) {
  154 + $expected = new ExceptionExpectation($expected);
  155 + }
  156 + $this->expected = $expected;
  157 + $this->message = $message;
  158 + }
  159 +
  160 + /**
  161 + * Compares the expected exception with any
  162 + * in the queue. Issues a pass or fail and
  163 + * returns the state of the test.
  164 + * @param SimpleTestCase $test Test case to send messages to.
  165 + * @param Exception $exception Exception to compare.
  166 + * @return boolean False on no match.
  167 + */
  168 + function isExpected($test, $exception) {
  169 + if ($this->expected) {
  170 + return $test->assert($this->expected, $exception, $this->message);
  171 + }
  172 + return false;
  173 + }
  174 +
  175 + /**
  176 + * Tests for any left over exception.
  177 + * @return string/false The failure message or false if none.
  178 + */
  179 + function getOutstanding() {
  180 + return sprintf($this->message, 'Failed to trap exception');
  181 + }
  182 +
  183 + /**
  184 + * Discards the contents of the error queue.
  185 + */
  186 + function clear() {
  187 + $this->expected = false;
  188 + $this->message = false;
  189 + }
  190 + }
  191 +?>
0 \ No newline at end of file 192 \ No newline at end of file
thirdparty/simpletest/simpletest/expectation.php
@@ -30,7 +30,6 @@ @@ -30,7 +30,6 @@
30 * @param string $message Customised message on failure. 30 * @param string $message Customised message on failure.
31 */ 31 */
32 function SimpleExpectation($message = '%s') { 32 function SimpleExpectation($message = '%s') {
33 - $this->_dumper = &new SimpleDumper();  
34 $this->_message = $message; 33 $this->_message = $message;
35 } 34 }
36 35
@@ -58,12 +57,14 @@ @@ -58,12 +57,14 @@
58 /** 57 /**
59 * Overlays the generated message onto the stored user 58 * Overlays the generated message onto the stored user
60 * message. An additional message can be interjected. 59 * message. An additional message can be interjected.
61 - * @param mixed $compare Comparison value.  
62 - * @return string Description of success  
63 - * or failure. 60 + * @param mixed $compare Comparison value.
  61 + * @param SimpleDumper $dumper For formatting the results.
  62 + * @return string Description of success
  63 + * or failure.
64 * @access public 64 * @access public
65 */ 65 */
66 - function overlayMessage($compare) { 66 + function overlayMessage($compare, $dumper) {
  67 + $this->_dumper = $dumper;
67 return sprintf($this->_message, $this->testMessage($compare)); 68 return sprintf($this->_message, $this->testMessage($compare));
68 } 69 }
69 70
@@ -91,6 +92,96 @@ @@ -91,6 +92,96 @@
91 SimpleTestCompatibility::isA($expectation, 'SimpleExpectation'); 92 SimpleTestCompatibility::isA($expectation, 'SimpleExpectation');
92 } 93 }
93 } 94 }
  95 +
  96 + /**
  97 + * A wildcard expectation always matches.
  98 + * @package SimpleTest
  99 + * @subpackage MockObjects
  100 + */
  101 + class AnythingExpectation extends SimpleExpectation {
  102 +
  103 + /**
  104 + * Tests the expectation. Always true.
  105 + * @param mixed $compare Ignored.
  106 + * @return boolean True.
  107 + * @access public
  108 + */
  109 + function test($compare) {
  110 + return true;
  111 + }
  112 +
  113 + /**
  114 + * Returns a human readable test message.
  115 + * @param mixed $compare Comparison value.
  116 + * @return string Description of success
  117 + * or failure.
  118 + * @access public
  119 + */
  120 + function testMessage($compare) {
  121 + $dumper = &$this->_getDumper();
  122 + return 'Anything always matches [' . $dumper->describeValue($compare) . ']';
  123 + }
  124 + }
  125 +
  126 + /**
  127 + * An expectation that passes on boolean true.
  128 + * @package SimpleTest
  129 + * @subpackage MockObjects
  130 + */
  131 + class TrueExpectation extends SimpleExpectation {
  132 +
  133 + /**
  134 + * Tests the expectation.
  135 + * @param mixed $compare Should be true.
  136 + * @return boolean True on match.
  137 + * @access public
  138 + */
  139 + function test($compare) {
  140 + return (boolean)$compare;
  141 + }
  142 +
  143 + /**
  144 + * Returns a human readable test message.
  145 + * @param mixed $compare Comparison value.
  146 + * @return string Description of success
  147 + * or failure.
  148 + * @access public
  149 + */
  150 + function testMessage($compare) {
  151 + $dumper = &$this->_getDumper();
  152 + return 'Expected true, got [' . $dumper->describeValue($compare) . ']';
  153 + }
  154 + }
  155 +
  156 + /**
  157 + * An expectation that passes on boolean false.
  158 + * @package SimpleTest
  159 + * @subpackage MockObjects
  160 + */
  161 + class FalseExpectation extends SimpleExpectation {
  162 +
  163 + /**
  164 + * Tests the expectation.
  165 + * @param mixed $compare Should be false.
  166 + * @return boolean True on match.
  167 + * @access public
  168 + */
  169 + function test($compare) {
  170 + return ! (boolean)$compare;
  171 + }
  172 +
  173 + /**
  174 + * Returns a human readable test message.
  175 + * @param mixed $compare Comparison value.
  176 + * @return string Description of success
  177 + * or failure.
  178 + * @access public
  179 + */
  180 + function testMessage($compare) {
  181 + $dumper = &$this->_getDumper();
  182 + return 'Expected false, got [' . $dumper->describeValue($compare) . ']';
  183 + }
  184 + }
94 185
95 /** 186 /**
96 * Test for equality. 187 * Test for equality.
@@ -471,8 +562,8 @@ @@ -471,8 +562,8 @@
471 /** 562 /**
472 * Describes a pattern match including the string 563 * Describes a pattern match including the string
473 * found and it's position. 564 * found and it's position.
474 - * @package SimpleTest  
475 - * @subpackage UnitTester 565 + * @package SimpleTest
  566 + * @subpackage UnitTester
476 * @param string $pattern Regex to match against. 567 * @param string $pattern Regex to match against.
477 * @param string $subject Subject to search. 568 * @param string $subject Subject to search.
478 * @access protected 569 * @access protected
@@ -480,7 +571,7 @@ @@ -480,7 +571,7 @@
480 function _describePatternMatch($pattern, $subject) { 571 function _describePatternMatch($pattern, $subject) {
481 preg_match($pattern, $subject, $matches); 572 preg_match($pattern, $subject, $matches);
482 $position = strpos($subject, $matches[0]); 573 $position = strpos($subject, $matches[0]);
483 - $dumper = &$this->_getDumper(); 574 + $dumper = $this->_getDumper();
484 return "Pattern [$pattern] detected at character [$position] in [" . 575 return "Pattern [$pattern] detected at character [$position] in [" .
485 $dumper->describeValue($subject) . "] as [" . 576 $dumper->describeValue($subject) . "] as [" .
486 $matches[0] . "] in region [" . 577 $matches[0] . "] in region [" .
@@ -717,4 +808,4 @@ @@ -717,4 +808,4 @@
717 "] should contain method [$method]"; 808 "] should contain method [$method]";
718 } 809 }
719 } 810 }
720 -?> 811 -?>
  812 +?>
721 \ No newline at end of file 813 \ No newline at end of file
thirdparty/simpletest/simpletest/extensions/pear_test_case.php
@@ -58,7 +58,7 @@ @@ -58,7 +58,7 @@
58 * @public 58 * @public
59 */ 59 */
60 function assertNotNull($value, $message = "%s") { 60 function assertNotNull($value, $message = "%s") {
61 - parent::assertTrue(isset($value), $message); 61 + parent::assert(new TrueExpectation(), isset($value), $message);
62 } 62 }
63 63
64 /** 64 /**
@@ -68,7 +68,7 @@ @@ -68,7 +68,7 @@
68 * @public 68 * @public
69 */ 69 */
70 function assertNull($value, $message = "%s") { 70 function assertNull($value, $message = "%s") {
71 - parent::assertTrue(!isset($value), $message); 71 + parent::assert(new TrueExpectation(), !isset($value), $message);
72 } 72 }
73 73
74 /** 74 /**
@@ -86,7 +86,8 @@ @@ -86,7 +86,8 @@
86 "[" . $dumper->describeValue($first) . 86 "[" . $dumper->describeValue($first) .
87 "] and [" . $dumper->describeValue($second) . 87 "] and [" . $dumper->describeValue($second) .
88 "] should reference the same object"); 88 "] should reference the same object");
89 - return $this->assertTrue( 89 + return $this->assert(
  90 + new TrueExpectation(),
90 SimpleTestCompatibility::isReference($first, $second), 91 SimpleTestCompatibility::isReference($first, $second),
91 $message); 92 $message);
92 } 93 }
@@ -106,7 +107,8 @@ @@ -106,7 +107,8 @@
106 "[" . $dumper->describeValue($first) . 107 "[" . $dumper->describeValue($first) .
107 "] and [" . $dumper->describeValue($second) . 108 "] and [" . $dumper->describeValue($second) .
108 "] should not be the same object"); 109 "] should not be the same object");
109 - return $this->assertFalse( 110 + return $this->assert(
  111 + new falseExpectation(),
110 SimpleTestCompatibility::isReference($first, $second), 112 SimpleTestCompatibility::isReference($first, $second),
111 $message); 113 $message);
112 } 114 }
@@ -119,7 +121,7 @@ @@ -119,7 +121,7 @@
119 * @public 121 * @public
120 */ 122 */
121 function assertTrue($condition, $message = "%s") { 123 function assertTrue($condition, $message = "%s") {
122 - parent::assertTrue($condition, $message); 124 + parent::assert(new TrueExpectation(), $condition, $message);
123 } 125 }
124 126
125 /** 127 /**
@@ -130,7 +132,7 @@ @@ -130,7 +132,7 @@
130 * @public 132 * @public
131 */ 133 */
132 function assertFalse($condition, $message = "%s") { 134 function assertFalse($condition, $message = "%s") {
133 - parent::assertTrue(!$condition, $message); 135 + parent::assert(new FalseExpectation(), $condition, $message);
134 } 136 }
135 137
136 /** 138 /**
@@ -152,7 +154,7 @@ @@ -152,7 +154,7 @@
152 * @public 154 * @public
153 */ 155 */
154 function assertType($value, $type, $message = "%s") { 156 function assertType($value, $type, $message = "%s") {
155 - parent::assertTrue(gettype($value) == strtolower($type), $message); 157 + parent::assert(new TrueExpectation(), gettype($value) == strtolower($type), $message);
156 } 158 }
157 159
158 /** 160 /**
thirdparty/simpletest/simpletest/extensions/phpunit_test_case.php
@@ -38,7 +38,7 @@ @@ -38,7 +38,7 @@
38 * @public 38 * @public
39 */ 39 */
40 function assert($condition, $message = false) { 40 function assert($condition, $message = false) {
41 - parent::assertTrue($condition, $message); 41 + parent::assert(new TrueExpectation(), $condition, $message);
42 } 42 }
43 43
44 /** 44 /**
thirdparty/simpletest/simpletest/mock_objects.php
@@ -27,36 +27,6 @@ @@ -27,36 +27,6 @@
27 } 27 }
28 28
29 /** 29 /**
30 - * A wildcard expectation always matches.  
31 - * @package SimpleTest  
32 - * @subpackage MockObjects  
33 - */  
34 - class AnythingExpectation extends SimpleExpectation {  
35 -  
36 - /**  
37 - * Tests the expectation. Always true.  
38 - * @param mixed $compare Ignored.  
39 - * @return boolean True.  
40 - * @access public  
41 - */  
42 - function test($compare) {  
43 - return true;  
44 - }  
45 -  
46 - /**  
47 - * Returns a human readable test message.  
48 - * @param mixed $compare Comparison value.  
49 - * @return string Description of success  
50 - * or failure.  
51 - * @access public  
52 - */  
53 - function testMessage($compare) {  
54 - $dumper = &$this->_getDumper();  
55 - return 'Anything always matches [' . $dumper->describeValue($compare) . ']';  
56 - }  
57 - }  
58 -  
59 - /**  
60 * Parameter comparison assertion. 30 * Parameter comparison assertion.
61 * @package SimpleTest 31 * @package SimpleTest
62 * @subpackage MockObjects 32 * @subpackage MockObjects
@@ -70,8 +40,6 @@ @@ -70,8 +40,6 @@
70 * those that are wildcarded. 40 * those that are wildcarded.
71 * If the value is not an array 41 * If the value is not an array
72 * then it is considered to match any. 42 * then it is considered to match any.
73 - * @param mixed $wildcard Any parameter matching this  
74 - * will always match.  
75 * @param string $message Customised message on failure. 43 * @param string $message Customised message on failure.
76 * @access public 44 * @access public
77 */ 45 */
@@ -151,7 +119,7 @@ @@ -151,7 +119,7 @@
151 $comparison = $this->_coerceToExpectation($expected[$i]); 119 $comparison = $this->_coerceToExpectation($expected[$i]);
152 if (! $comparison->test($parameters[$i])) { 120 if (! $comparison->test($parameters[$i])) {
153 $messages[] = "parameter " . ($i + 1) . " with [" . 121 $messages[] = "parameter " . ($i + 1) . " with [" .
154 - $comparison->overlayMessage($parameters[$i]) . "]"; 122 + $comparison->overlayMessage($parameters[$i], $this->_getDumper()) . "]";
155 } 123 }
156 } 124 }
157 return "Parameter expectation differs at " . implode(" and ", $messages); 125 return "Parameter expectation differs at " . implode(" and ", $messages);
@@ -473,7 +441,8 @@ @@ -473,7 +441,8 @@
473 * @access protected 441 * @access protected
474 */ 442 */
475 function &_getCurrentTestCase() { 443 function &_getCurrentTestCase() {
476 - return SimpleTest::getCurrent(); 444 + $context = &SimpleTest::getContext();
  445 + return $context->getTest();
477 } 446 }
478 447
479 /** 448 /**
@@ -809,20 +778,17 @@ @@ -809,20 +778,17 @@
809 * test method has finished. Totals up the call 778 * test method has finished. Totals up the call
810 * counts and triggers a test assertion if a test 779 * counts and triggers a test assertion if a test
811 * is present for expected call counts. 780 * is present for expected call counts.
812 - * @param string $method Current method name. 781 + * @param string $test_method Current method name.
  782 + * @param SimpleTestCase $test Test to send message to.
813 * @access public 783 * @access public
814 */ 784 */
815 - function atTestEnd($method) { 785 + function atTestEnd($test_method, &$test) {
816 foreach ($this->_expected_counts as $method => $expectation) { 786 foreach ($this->_expected_counts as $method => $expectation) {
817 - $this->_assertTrue(  
818 - $expectation->test($this->getCallCount($method)),  
819 - $expectation->overlayMessage($this->getCallCount($method))); 787 + $test->assert($expectation, $this->getCallCount($method));
820 } 788 }
821 foreach ($this->_max_counts as $method => $expectation) { 789 foreach ($this->_max_counts as $method => $expectation) {
822 if ($expectation->test($this->getCallCount($method))) { 790 if ($expectation->test($this->getCallCount($method))) {
823 - $this->_assertTrue(  
824 - true,  
825 - $expectation->overlayMessage($this->getCallCount($method))); 791 + $test->assert($expectation, $this->getCallCount($method));
826 } 792 }
827 } 793 }
828 } 794 }
@@ -880,39 +846,24 @@ @@ -880,39 +846,24 @@
880 * @access private 846 * @access private
881 */ 847 */
882 function _checkExpectations($method, $args, $timing) { 848 function _checkExpectations($method, $args, $timing) {
  849 + $test = &$this->_getCurrentTestCase();
883 if (isset($this->_max_counts[$method])) { 850 if (isset($this->_max_counts[$method])) {
884 if (! $this->_max_counts[$method]->test($timing + 1)) { 851 if (! $this->_max_counts[$method]->test($timing + 1)) {
885 - $this->_assertTrue(  
886 - false,  
887 - $this->_max_counts[$method]->overlayMessage($timing + 1)); 852 + $test->assert($this->_max_counts[$method], $timing + 1);
888 } 853 }
889 } 854 }
890 if (isset($this->_expected_args_at[$timing][$method])) { 855 if (isset($this->_expected_args_at[$timing][$method])) {
891 - $this->_assertTrue(  
892 - $this->_expected_args_at[$timing][$method]->test($args),  
893 - "Mock method [$method] at [$timing] -> " .  
894 - $this->_expected_args_at[$timing][$method]->overlayMessage($args)); 856 + $test->assert(
  857 + $this->_expected_args_at[$timing][$method],
  858 + $args,
  859 + "Mock method [$method] at [$timing] -> %s");
895 } elseif (isset($this->_expected_args[$method])) { 860 } elseif (isset($this->_expected_args[$method])) {
896 - $this->_assertTrue(  
897 - $this->_expected_args[$method]->test($args),  
898 - "Mock method [$method] -> " . $this->_expected_args[$method]->overlayMessage($args)); 861 + $test->assert(
  862 + $this->_expected_args[$method],
  863 + $args,
  864 + "Mock method [$method] -> %s");
899 } 865 }
900 } 866 }
901 -  
902 - /**  
903 - * Triggers an assertion on the held test case.  
904 - * Should be overridden when using another test  
905 - * framework other than the SimpleTest one if the  
906 - * assertion method has a different name.  
907 - * @param boolean $assertion True will pass.  
908 - * @param string $message Message that will go with  
909 - * the test event.  
910 - * @access protected  
911 - */  
912 - function _assertTrue($assertion, $message) {  
913 - $test = &$this->_getCurrentTestCase();  
914 - $test->assertTrue($assertion, $message);  
915 - }  
916 } 867 }
917 868
918 /** 869 /**
@@ -928,7 +879,7 @@ @@ -928,7 +879,7 @@
928 * @access public 879 * @access public
929 */ 880 */
930 function Mock() { 881 function Mock() {
931 - trigger_error('Mock factory methods are class only.'); 882 + trigger_error('Mock factory methods are static.');
932 } 883 }
933 884
934 /** 885 /**
@@ -970,19 +921,12 @@ @@ -970,19 +921,12 @@
970 921
971 /** 922 /**
972 * Uses a stack trace to find the line of an assertion. 923 * Uses a stack trace to find the line of an assertion.
973 - * @param array $stack Stack frames top most first. Only  
974 - * needed if not using the PHP  
975 - * backtrace function.  
976 - * @return string Location of first expect*  
977 - * method embedded in format string.  
978 * @access public 924 * @access public
979 * @static 925 * @static
980 */ 926 */
981 - function getExpectationLine($stack = false) {  
982 - if ($stack === false) {  
983 - $stack = SimpleTestCompatibility::getStackTrace();  
984 - }  
985 - return SimpleDumper::getFormattedAssertionLine($stack); 927 + function getExpectationLine() {
  928 + $trace = new SimpleStackTrace(array('expect'));
  929 + return $trace->traceMethod();
986 } 930 }
987 } 931 }
988 932
@@ -1051,7 +995,7 @@ @@ -1051,7 +995,7 @@
1051 } 995 }
1052 $mock_reflection = new SimpleReflection($this->_mock_class); 996 $mock_reflection = new SimpleReflection($this->_mock_class);
1053 if ($mock_reflection->classExistsSansAutoload()) { 997 if ($mock_reflection->classExistsSansAutoload()) {
1054 - trigger_error("Partial mock class [$mock_class] already exists"); 998 + trigger_error('Partial mock class [' . $this->_mock_class . '] already exists');
1055 return false; 999 return false;
1056 } 1000 }
1057 return eval($this->_extendClassCode($methods)); 1001 return eval($this->_extendClassCode($methods));
thirdparty/simpletest/simpletest/parser.php
@@ -645,13 +645,15 @@ @@ -645,13 +645,15 @@
645 * @access public 645 * @access public
646 */ 646 */
647 function acceptAttributeToken($token, $event) { 647 function acceptAttributeToken($token, $event) {
648 - if ($event == LEXER_UNMATCHED) {  
649 - $this->_attributes[$this->_current_attribute] .=  
650 - SimpleHtmlSaxParser::decodeHtml($token);  
651 - }  
652 - if ($event == LEXER_SPECIAL) {  
653 - $this->_attributes[$this->_current_attribute] .=  
654 - preg_replace('/^=\s*/' , '', SimpleHtmlSaxParser::decodeHtml($token)); 648 + if ($this->_current_attribute) {
  649 + if ($event == LEXER_UNMATCHED) {
  650 + $this->_attributes[$this->_current_attribute] .=
  651 + SimpleHtmlSaxParser::decodeHtml($token);
  652 + }
  653 + if ($event == LEXER_SPECIAL) {
  654 + $this->_attributes[$this->_current_attribute] .=
  655 + preg_replace('/^=\s*/' , '', SimpleHtmlSaxParser::decodeHtml($token));
  656 + }
655 } 657 }
656 return true; 658 return true;
657 } 659 }
thirdparty/simpletest/simpletest/reflection_php5.php
@@ -8,8 +8,8 @@ @@ -8,8 +8,8 @@
8 8
9 /** 9 /**
10 * Version specific reflection API. 10 * Version specific reflection API.
11 - * @package SimpleTest  
12 - * @subpackage UnitTester 11 + * @package SimpleTest
  12 + * @subpackage UnitTester
13 */ 13 */
14 class SimpleReflection { 14 class SimpleReflection {
15 var $_interface; 15 var $_interface;
@@ -193,12 +193,17 @@ @@ -193,12 +193,17 @@
193 * @access public 193 * @access public
194 */ 194 */
195 function getSignature($name) { 195 function getSignature($name) {
196 - if ($name == '__get') {  
197 - return 'function __get($key)';  
198 - }  
199 if ($name == '__set') { 196 if ($name == '__set') {
200 return 'function __set($key, $value)'; 197 return 'function __set($key, $value)';
201 } 198 }
  199 + if ($name == '__call') {
  200 + return 'function __call($method, $arguments)';
  201 + }
  202 + if (version_compare(phpversion(), '5.1.0', '>=')) {
  203 + if (in_array($name, array('__get', '__isset', $name == '__unset'))) {
  204 + return "function {$name}(\$key)";
  205 + }
  206 + }
202 if (! is_callable(array($this->_interface, $name))) { 207 if (! is_callable(array($this->_interface, $name))) {
203 return "function $name()"; 208 return "function $name()";
204 } 209 }
@@ -217,31 +222,31 @@ @@ -217,31 +222,31 @@
217 * @access private 222 * @access private
218 */ 223 */
219 function _getFullSignature($name) { 224 function _getFullSignature($name) {
220 - $interface = new ReflectionClass($this->_interface);  
221 - $method = $interface->getMethod($name);  
222 - $reference = $method->returnsReference() ? '&' : '';  
223 - return "function $reference$name(" .  
224 - implode(', ', $this->_getParameterSignatures($method)) .  
225 - ")"; 225 + $interface = new ReflectionClass($this->_interface);
  226 + $method = $interface->getMethod($name);
  227 + $reference = $method->returnsReference() ? '&' : '';
  228 + return "function $reference$name(" .
  229 + implode(', ', $this->_getParameterSignatures($method)) .
  230 + ")";
226 } 231 }
227 232
228 /** 233 /**
229 * Gets the source code for each parameter. 234 * Gets the source code for each parameter.
230 * @param ReflectionMethod $method Method object from 235 * @param ReflectionMethod $method Method object from
231 - * reflection API 236 + * reflection API
232 * @return array List of strings, each 237 * @return array List of strings, each
233 * a snippet of code. 238 * a snippet of code.
234 * @access private 239 * @access private
235 */ 240 */
236 function _getParameterSignatures($method) { 241 function _getParameterSignatures($method) {
237 - $signatures = array(); 242 + $signatures = array();
238 foreach ($method->getParameters() as $parameter) { 243 foreach ($method->getParameters() as $parameter) {
239 $type = $parameter->getClass(); 244 $type = $parameter->getClass();
240 $signatures[] = 245 $signatures[] =
241 - (! is_null($type) ? $type->getName() . ' ' : '') .  
242 - ($parameter->isPassedByReference() ? '&' : '') .  
243 - '$' . $this->_suppressSpurious($parameter->getName()) .  
244 - ($this->_isOptional($parameter) ? ' = null' : ''); 246 + (! is_null($type) ? $type->getName() . ' ' : '') .
  247 + ($parameter->isPassedByReference() ? '&' : '') .
  248 + '$' . $this->_suppressSpurious($parameter->getName()) .
  249 + ($this->_isOptional($parameter) ? ' = null' : '');
245 } 250 }
246 return $signatures; 251 return $signatures;
247 } 252 }
thirdparty/simpletest/simpletest/remote.php
@@ -75,7 +75,8 @@ @@ -75,7 +75,8 @@
75 * @access protected 75 * @access protected
76 */ 76 */
77 function &_createBrowser() { 77 function &_createBrowser() {
78 - return new SimpleBrowser(); 78 + $browser = &new SimpleBrowser();
  79 + return $browser;
79 } 80 }
80 81
81 /** 82 /**
@@ -85,7 +86,8 @@ @@ -85,7 +86,8 @@
85 * @access protected 86 * @access protected
86 */ 87 */
87 function &_createParser(&$reporter) { 88 function &_createParser(&$reporter) {
88 - return new SimpleTestXmlParser($reporter); 89 + $parser = &new SimpleTestXmlParser($reporter);
  90 + return $parser;
89 } 91 }
90 92
91 /** 93 /**
thirdparty/simpletest/simpletest/reporter.php
@@ -40,6 +40,7 @@ @@ -40,6 +40,7 @@
40 */ 40 */
41 function paintHeader($test_name) { 41 function paintHeader($test_name) {
42 $this->sendNoCacheHeaders(); 42 $this->sendNoCacheHeaders();
  43 + print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">";
43 print "<html>\n<head>\n<title>$test_name</title>\n"; 44 print "<html>\n<head>\n<title>$test_name</title>\n";
44 print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=" . 45 print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=" .
45 $this->_character_set . "\">\n"; 46 $this->_character_set . "\">\n";
@@ -74,7 +75,9 @@ @@ -74,7 +75,9 @@
74 * @access protected 75 * @access protected
75 */ 76 */
76 function _getCss() { 77 function _getCss() {
77 - return ".fail { color: red; } pre { background-color: lightgray; }"; 78 + return ".fail { background-color: inherit; color: red; }" .
  79 + ".pass { background-color: inherit; color: green; }" .
  80 + " pre { background-color: lightgray; color: inherit; }";
78 } 81 }
79 82
80 /** 83 /**
@@ -115,10 +118,9 @@ @@ -115,10 +118,9 @@
115 } 118 }
116 119
117 /** 120 /**
118 - * Paints a PHP error or exception. 121 + * Paints a PHP error.
119 * @param string $message Message is ignored. 122 * @param string $message Message is ignored.
120 * @access public 123 * @access public
121 - * @abstract  
122 */ 124 */
123 function paintError($message) { 125 function paintError($message) {
124 parent::paintError($message); 126 parent::paintError($message);
@@ -130,6 +132,38 @@ @@ -130,6 +132,38 @@
130 } 132 }
131 133
132 /** 134 /**
  135 + * Paints a PHP exception.
  136 + * @param Exception $exception Exception to display.
  137 + * @access public
  138 + */
  139 + function paintException($exception) {
  140 + parent::paintException($exception);
  141 + print "<span class=\"fail\">Exception</span>: ";
  142 + $breadcrumb = $this->getTestList();
  143 + array_shift($breadcrumb);
  144 + print implode(" -&gt; ", $breadcrumb);
  145 + $message = 'Unexpected exception of type [' . get_class($exception) .
  146 + '] with message ['. $exception->getMessage() .
  147 + '] in ['. $exception->getFile() .
  148 + ' line ' . $exception->getLine() . ']';
  149 + print " -&gt; <strong>" . $this->_htmlEntities($message) . "</strong><br />\n";
  150 + }
  151 +
  152 + /**
  153 + * Prints the message for skipping tests.
  154 + * @param string $message Text of skip condition.
  155 + * @access public
  156 + */
  157 + function paintSkip($message) {
  158 + parent::paintSkip($message);
  159 + print "<span class=\"pass\">Skipped</span>: ";
  160 + $breadcrumb = $this->getTestList();
  161 + array_shift($breadcrumb);
  162 + print implode(" -&gt; ", $breadcrumb);
  163 + print " -&gt; " . $this->_htmlEntities($message) . "<br />\n";
  164 + }
  165 +
  166 + /**
133 * Paints formatted text such as dumped variables. 167 * Paints formatted text such as dumped variables.
134 * @param string $message Text to show. 168 * @param string $message Text to show.
135 * @access public 169 * @access public
@@ -218,7 +252,7 @@ @@ -218,7 +252,7 @@
218 252
219 /** 253 /**
220 * Paints a PHP error or exception. 254 * Paints a PHP error or exception.
221 - * @param string $message Message is ignored. 255 + * @param string $message Message to be shown.
222 * @access public 256 * @access public
223 * @abstract 257 * @abstract
224 */ 258 */
@@ -228,6 +262,31 @@ @@ -228,6 +262,31 @@
228 } 262 }
229 263
230 /** 264 /**
  265 + * Paints a PHP error or exception.
  266 + * @param Exception $exception Exception to describe.
  267 + * @access public
  268 + * @abstract
  269 + */
  270 + function paintException($exception) {
  271 + parent::paintException($exception);
  272 + $message = 'Unexpected exception of type [' . get_class($exception) .
  273 + '] with message ['. $exception->getMessage() .
  274 + '] in ['. $exception->getFile() .
  275 + ' line ' . $exception->getLine() . ']';
  276 + print "Exception " . $this->getExceptionCount() . "!\n$message\n";
  277 + }
  278 +
  279 + /**
  280 + * Prints the message for skipping tests.
  281 + * @param string $message Text of skip condition.
  282 + * @access public
  283 + */
  284 + function paintSkip($message) {
  285 + parent::paintSkip($message);
  286 + print "Skip: $message\n";
  287 + }
  288 +
  289 + /**
231 * Paints formatted text such as dumped variables. 290 * Paints formatted text such as dumped variables.
232 * @param string $message Text to show. 291 * @param string $message Text to show.
233 * @access public 292 * @access public
thirdparty/simpletest/simpletest/scorer.php
@@ -149,8 +149,7 @@ @@ -149,8 +149,7 @@
149 } 149 }
150 150
151 /** 151 /**
152 - * Deals with PHP 4 throwing an error or PHP 5  
153 - * throwing an exception. 152 + * Deals with PHP 4 throwing an error.
154 * @param string $message Text of error formatted by 153 * @param string $message Text of error formatted by
155 * the test case. 154 * the test case.
156 * @access public 155 * @access public
@@ -160,6 +159,23 @@ @@ -160,6 +159,23 @@
160 } 159 }
161 160
162 /** 161 /**
  162 + * Deals with PHP 5 throwing an exception.
  163 + * @param Exception $exception The actual exception thrown.
  164 + * @access public
  165 + */
  166 + function paintException($exception) {
  167 + $this->_exceptions++;
  168 + }
  169 +
  170 + /**
  171 + * Prints the message for skipping tests.
  172 + * @param string $message Text of skip condition.
  173 + * @access public
  174 + */
  175 + function paintSkip($message) {
  176 + }
  177 +
  178 + /**
163 * Accessor for the number of passes so far. 179 * Accessor for the number of passes so far.
164 * @return integer Number of passes. 180 * @return integer Number of passes.
165 * @access public 181 * @access public
@@ -237,6 +253,16 @@ @@ -237,6 +253,16 @@
237 $this->_size = null; 253 $this->_size = null;
238 $this->_progress = 0; 254 $this->_progress = 0;
239 } 255 }
  256 +
  257 + /**
  258 + * Gets the formatter for variables and other small
  259 + * generic data items.
  260 + * @return SimpleDumper Formatter.
  261 + * @access public
  262 + */
  263 + function getDumper() {
  264 + return new SimpleDumper();
  265 + }
240 266
241 /** 267 /**
242 * Paints the start of a group test. Will also paint 268 * Paints the start of a group test. Will also paint
@@ -393,7 +419,7 @@ @@ -393,7 +419,7 @@
393 var $_reporter; 419 var $_reporter;
394 420
395 /** 421 /**
396 - * Mediates between teh reporter and the test case. 422 + * Mediates between the reporter and the test case.
397 * @param SimpleScorer $reporter Reporter to receive events. 423 * @param SimpleScorer $reporter Reporter to receive events.
398 */ 424 */
399 function SimpleReporterDecorator(&$reporter) { 425 function SimpleReporterDecorator(&$reporter) {
@@ -443,6 +469,16 @@ @@ -443,6 +469,16 @@
443 function &createInvoker(&$invoker) { 469 function &createInvoker(&$invoker) {
444 return $this->_reporter->createInvoker($invoker); 470 return $this->_reporter->createInvoker($invoker);
445 } 471 }
  472 +
  473 + /**
  474 + * Gets the formatter for variables and other small
  475 + * generic data items.
  476 + * @return SimpleDumper Formatter.
  477 + * @access public
  478 + */
  479 + function getDumper() {
  480 + return $this->_reporter->getDumper();
  481 + }
446 482
447 /** 483 /**
448 * Paints the start of a group test. 484 * Paints the start of a group test.
@@ -529,6 +565,24 @@ @@ -529,6 +565,24 @@
529 565
530 /** 566 /**
531 * Chains to the wrapped reporter. 567 * Chains to the wrapped reporter.
  568 + * @param Exception $exception Exception to show.
  569 + * @access public
  570 + */
  571 + function paintException($exception) {
  572 + $this->_reporter->paintException($exception);
  573 + }
  574 +
  575 + /**
  576 + * Prints the message for skipping tests.
  577 + * @param string $message Text of skip condition.
  578 + * @access public
  579 + */
  580 + function paintSkip($message) {
  581 + $this->_reporter->paintSkip($message);
  582 + }
  583 +
  584 + /**
  585 + * Chains to the wrapped reporter.
532 * @param string $message Text to display. 586 * @param string $message Text to display.
533 * @access public 587 * @access public
534 */ 588 */
@@ -635,6 +689,16 @@ @@ -635,6 +689,16 @@
635 } 689 }
636 return $invoker; 690 return $invoker;
637 } 691 }
  692 +
  693 + /**
  694 + * Gets the formatter for variables and other small
  695 + * generic data items.
  696 + * @return SimpleDumper Formatter.
  697 + * @access public
  698 + */
  699 + function getDumper() {
  700 + return new SimpleDumper();
  701 + }
638 702
639 /** 703 /**
640 * Paints the start of a group test. 704 * Paints the start of a group test.
@@ -736,6 +800,28 @@ @@ -736,6 +800,28 @@
736 $this->_reporters[$i]->paintError($message); 800 $this->_reporters[$i]->paintError($message);
737 } 801 }
738 } 802 }
  803 +
  804 + /**
  805 + * Chains to the wrapped reporter.
  806 + * @param Exception $exception Exception to display.
  807 + * @access public
  808 + */
  809 + function paintException($exception) {
  810 + for ($i = 0; $i < count($this->_reporters); $i++) {
  811 + $this->_reporters[$i]->paintException($exception);
  812 + }
  813 + }
  814 +
  815 + /**
  816 + * Prints the message for skipping tests.
  817 + * @param string $message Text of skip condition.
  818 + * @access public
  819 + */
  820 + function paintSkip($message) {
  821 + for ($i = 0; $i < count($this->_reporters); $i++) {
  822 + $this->_reporters[$i]->paintSkip($message);
  823 + }
  824 + }
739 825
740 /** 826 /**
741 * Chains to the wrapped reporter. 827 * Chains to the wrapped reporter.
thirdparty/simpletest/simpletest/shell_tester.php
@@ -63,7 +63,7 @@ @@ -63,7 +63,7 @@
63 63
64 /** 64 /**
65 * Test case for testing of command line scripts and 65 * Test case for testing of command line scripts and
66 - * utilities. Usually scripts taht are external to the 66 + * utilities. Usually scripts that are external to the
67 * PHP code, but support it in some way. 67 * PHP code, but support it in some way.
68 * @package SimpleTest 68 * @package SimpleTest
69 * @subpackage UnitTester 69 * @subpackage UnitTester
@@ -127,6 +127,33 @@ @@ -127,6 +127,33 @@
127 $shell = &$this->_getShell(); 127 $shell = &$this->_getShell();
128 return $shell->getOutputAsList(); 128 return $shell->getOutputAsList();
129 } 129 }
  130 +
  131 + /**
  132 + * Called from within the test methods to register
  133 + * passes and failures.
  134 + * @param boolean $result Pass on true.
  135 + * @param string $message Message to display describing
  136 + * the test state.
  137 + * @return boolean True on pass
  138 + * @access public
  139 + */
  140 + function assertTrue($result, $message = false) {
  141 + return $this->assert(new TrueExpectation(), $result, $message);
  142 + }
  143 +
  144 + /**
  145 + * Will be true on false and vice versa. False
  146 + * is the PHP definition of false, so that null,
  147 + * empty strings, zero and an empty array all count
  148 + * as false.
  149 + * @param boolean $result Pass on false.
  150 + * @param string $message Message to display.
  151 + * @return boolean True on pass
  152 + * @access public
  153 + */
  154 + function assertFalse($result, $message = '%s') {
  155 + return $this->assert(new FalseExpectation(), $result, $message);
  156 + }
130 157
131 /** 158 /**
132 * Will trigger a pass if the two parameters have 159 * Will trigger a pass if the two parameters have
@@ -303,4 +330,4 @@ @@ -303,4 +330,4 @@
303 return $shell; 330 return $shell;
304 } 331 }
305 } 332 }
306 -?>  
307 \ No newline at end of file 333 \ No newline at end of file
  334 +?>
thirdparty/simpletest/simpletest/simpletest.php
@@ -17,10 +17,8 @@ @@ -17,10 +17,8 @@
17 /**#@-*/ 17 /**#@-*/
18 18
19 /** 19 /**
20 - * Static global directives and options. I hate this  
21 - * class. It's a mixture of reference hacks, configuration  
22 - * and previous design screw-ups that I have to maintain  
23 - * to keep backward compatibility. 20 + * Registry and test context. Includes a few
  21 + * global options that I'm slowly getting rid of.
24 * @package SimpleTest 22 * @package SimpleTest
25 */ 23 */
26 class SimpleTest { 24 class SimpleTest {
@@ -59,8 +57,8 @@ @@ -59,8 +57,8 @@
59 * missing abstract declarations. This cannot 57 * missing abstract declarations. This cannot
60 * be done whilst loading classes wiithout forcing 58 * be done whilst loading classes wiithout forcing
61 * a particular order on the class declarations and 59 * a particular order on the class declarations and
62 - * the ignore() calls. It's nice to havethe ignore()  
63 - * calls at the top of teh file. 60 + * the ignore() calls. It's just nice to have the ignore()
  61 + * calls at the top of the file before the actual declarations.
64 * @param array $classes Class names of interest. 62 * @param array $classes Class names of interest.
65 * @static 63 * @static
66 * @access public 64 * @access public
@@ -157,30 +155,6 @@ @@ -157,30 +155,6 @@
157 } 155 }
158 156
159 /** 157 /**
160 - * Sets the current test case instance. This  
161 - * global instance can be used by the mock objects  
162 - * to send message to the test cases.  
163 - * @param SimpleTestCase $test Test case to register.  
164 - * @access public  
165 - * @static  
166 - */  
167 - function setCurrent(&$test) {  
168 - $registry = &SimpleTest::_getRegistry();  
169 - $registry['CurrentTestCase'] = &$test;  
170 - }  
171 -  
172 - /**  
173 - * Accessor for current test instance.  
174 - * @return SimpleTEstCase Currently running test.  
175 - * @access public  
176 - * @static  
177 - */  
178 - function &getCurrent() {  
179 - $registry = &SimpleTest::_getRegistry();  
180 - return $registry['CurrentTestCase'];  
181 - }  
182 -  
183 - /**  
184 * Accessor for global registry of options. 158 * Accessor for global registry of options.
185 * @return hash All stored values. 159 * @return hash All stored values.
186 * @access private 160 * @access private
@@ -195,6 +169,21 @@ @@ -195,6 +169,21 @@
195 } 169 }
196 170
197 /** 171 /**
  172 + * Accessor for the context of the current
  173 + * test run.
  174 + * @return SimpleTestContext Current test run.
  175 + * @access public
  176 + * @static
  177 + */
  178 + function &getContext() {
  179 + static $context = false;
  180 + if (! $context) {
  181 + $context = new SimpleTestContext();
  182 + }
  183 + return $context;
  184 + }
  185 +
  186 + /**
198 * Constant default values. 187 * Constant default values.
199 * @return hash All registry defaults. 188 * @return hash All registry defaults.
200 * @access private 189 * @access private
@@ -212,6 +201,168 @@ @@ -212,6 +201,168 @@
212 } 201 }
213 202
214 /** 203 /**
  204 + * Container for all components for a specific
  205 + * test run. Makes things like error queues
  206 + * available to PHP event handlers, and also
  207 + * gets around some nasty reference issues in
  208 + * the mocks.
  209 + * @package SimpleTest
  210 + */
  211 + class SimpleTestContext {
  212 + var $_test;
  213 + var $_reporter;
  214 + var $_resources;
  215 +
  216 + /**
  217 + * Clears down the current context.
  218 + * @access public
  219 + */
  220 + function clear() {
  221 + $this->_resources = array();
  222 + }
  223 +
  224 + /**
  225 + * Sets the current test case instance. This
  226 + * global instance can be used by the mock objects
  227 + * to send message to the test cases.
  228 + * @param SimpleTestCase $test Test case to register.
  229 + * @access public
  230 + */
  231 + function setTest(&$test) {
  232 + $this->clear();
  233 + $this->_test = &$test;
  234 + }
  235 +
  236 + /**
  237 + * Accessor for currently running test case.
  238 + * @return SimpleTestCase Current test.
  239 + * @acess pubic
  240 + */
  241 + function &getTest() {
  242 + return $this->_test;
  243 + }
  244 +
  245 + /**
  246 + * Sets the current reporter. This
  247 + * global instance can be used by the mock objects
  248 + * to send messages.
  249 + * @param SimpleReporter $reporter Reporter to register.
  250 + * @access public
  251 + */
  252 + function setReporter(&$reporter) {
  253 + $this->clear();
  254 + $this->_reporter = &$reporter;
  255 + }
  256 +
  257 + /**
  258 + * Accessor for current reporter.
  259 + * @return SimpleReporter Current reporter.
  260 + * @acess pubic
  261 + */
  262 + function &getReporter() {
  263 + return $this->_reporter;
  264 + }
  265 +
  266 + /**
  267 + * Accessor for the Singleton resource.
  268 + * @return object Global resource.
  269 + * @access public
  270 + * @static
  271 + */
  272 + function &get($resource) {
  273 + if (! isset($this->_resources[$resource])) {
  274 + $this->_resources[$resource] = &new $resource();
  275 + }
  276 + return $this->_resources[$resource];
  277 + }
  278 + }
  279 +
  280 + /**
  281 + * Interrogates the stack trace to recover the
  282 + * failure point.
  283 + * @package SimpleTest
  284 + * @subpackage UnitTester
  285 + */
  286 + class SimpleStackTrace {
  287 + var $_prefixes;
  288 +
  289 + /**
  290 + * Stashes the list of target prefixes.
  291 + * @param array $prefixes List of method prefixes
  292 + * to search for.
  293 + */
  294 + function SimpleStackTrace($prefixes) {
  295 + $this->_prefixes = $prefixes;
  296 + }
  297 +
  298 + /**
  299 + * Extracts the last method name that was not within
  300 + * Simpletest itself. Captures a stack trace if none given.
  301 + * @param array $stack List of stack frames.
  302 + * @return string Snippet of test report with line
  303 + * number and file.
  304 + * @access public
  305 + */
  306 + function traceMethod($stack = false) {
  307 + $stack = $stack ? $stack : $this->_captureTrace();
  308 + foreach ($stack as $frame) {
  309 + if ($this->_frameLiesWithinSimpleTestFolder($frame)) {
  310 + continue;
  311 + }
  312 + if ($this->_frameMatchesPrefix($frame)) {
  313 + return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ']';
  314 + }
  315 + }
  316 + return '';
  317 + }
  318 +
  319 + /**
  320 + * Test to see if error is generated by SimpleTest itself.
  321 + * @param array $frame PHP stack frame.
  322 + * @return boolean True if a SimpleTest file.
  323 + * @access private
  324 + */
  325 + function _frameLiesWithinSimpleTestFolder($frame) {
  326 + if (isset($frame['file'])) {
  327 + $path = substr(SIMPLE_TEST, 0, -1);
  328 + if (strpos($frame['file'], $path) === 0) {
  329 + if (dirname($frame['file']) == $path) {
  330 + return true;
  331 + }
  332 + }
  333 + }
  334 + return false;
  335 + }
  336 +
  337 + /**
  338 + * Tries to determine if the method call is an assert, etc.
  339 + * @param array $frame PHP stack frame.
  340 + * @return boolean True if matches a target.
  341 + * @access private
  342 + */
  343 + function _frameMatchesPrefix($frame) {
  344 + foreach ($this->_prefixes as $prefix) {
  345 + if (strncmp($frame['function'], $prefix, strlen($prefix)) == 0) {
  346 + return true;
  347 + }
  348 + }
  349 + return false;
  350 + }
  351 +
  352 + /**
  353 + * Grabs a current stack trace.
  354 + * @return array Fulle trace.
  355 + * @access private
  356 + */
  357 + function _captureTrace() {
  358 + if (function_exists('debug_backtrace')) {
  359 + return array_reverse(debug_backtrace());
  360 + }
  361 + return array();
  362 + }
  363 + }
  364 +
  365 + /**
215 * @deprecated 366 * @deprecated
216 */ 367 */
217 class SimpleTestOptions extends SimpleTest { 368 class SimpleTestOptions extends SimpleTest {
@@ -279,4 +430,4 @@ @@ -279,4 +430,4 @@
279 return Simpletest::getDefaultProxyPassword(); 430 return Simpletest::getDefaultProxyPassword();
280 } 431 }
281 } 432 }
282 -?>  
283 \ No newline at end of file 433 \ No newline at end of file
  434 +?>
thirdparty/simpletest/simpletest/test_case.php
@@ -24,10 +24,8 @@ @@ -24,10 +24,8 @@
24 require_once(dirname(__FILE__) . '/reflection_php4.php'); 24 require_once(dirname(__FILE__) . '/reflection_php4.php');
25 } 25 }
26 if (! defined('SIMPLE_TEST')) { 26 if (! defined('SIMPLE_TEST')) {
27 - /**  
28 - * @ignore  
29 - */  
30 - define('SIMPLE_TEST', dirname(__FILE__) . '/'); 27 + /** @ignore */
  28 + define('SIMPLE_TEST', dirname(__FILE__) . DIRECTORY_SEPARATOR);
31 } 29 }
32 /**#@-*/ 30 /**#@-*/
33 31
@@ -43,6 +41,7 @@ @@ -43,6 +41,7 @@
43 var $_label = false; 41 var $_label = false;
44 var $_reporter; 42 var $_reporter;
45 var $_observers; 43 var $_observers;
  44 + var $_should_skip = false;
46 45
47 /** 46 /**
48 * Sets up the test with no display. 47 * Sets up the test with no display.
@@ -66,6 +65,41 @@ @@ -66,6 +65,41 @@
66 } 65 }
67 66
68 /** 67 /**
  68 + * This is a placeholder for skipping tests. In this
  69 + * method you place skipIf() and skipUnless() calls to
  70 + * set the skipping state.
  71 + * @access public
  72 + */
  73 + function skip() {
  74 + }
  75 +
  76 + /**
  77 + * Will issue a message to the reporter and tell the test
  78 + * case to skip if the incoming flag is true.
  79 + * @param string $should_skip Condition causing the tests to be skipped.
  80 + * @param string $message Text of skip condition.
  81 + * @access public
  82 + */
  83 + function skipIf($should_skip, $message = '%s') {
  84 + if ($should_skip && ! $this->_should_skip) {
  85 + $this->_should_skip = true;
  86 + $message = sprintf($message, 'Skipping [' . get_class($this) . ']');
  87 + $this->_reporter->paintSkip($message . $this->getAssertionLine());
  88 + }
  89 + }
  90 +
  91 + /**
  92 + * Will issue a message to the reporter and tell the test
  93 + * case to skip if the incoming flag is false.
  94 + * @param string $shouldnt_skip Condition causing the tests to be run.
  95 + * @param string $message Text of skip condition.
  96 + * @access public
  97 + */
  98 + function skipUnless($shouldnt_skip, $message = false) {
  99 + $this->skipIf(! $shouldnt_skip, $message);
  100 + }
  101 +
  102 + /**
69 * Used to invoke the single tests. 103 * Used to invoke the single tests.
70 * @return SimpleInvoker Individual test runner. 104 * @return SimpleInvoker Individual test runner.
71 * @access public 105 * @access public
@@ -83,21 +117,27 @@ @@ -83,21 +117,27 @@
83 * starting with the string "test" unless a method 117 * starting with the string "test" unless a method
84 * is specified. 118 * is specified.
85 * @param SimpleReporter $reporter Current test reporter. 119 * @param SimpleReporter $reporter Current test reporter.
  120 + * @return boolean True if all tests passed.
86 * @access public 121 * @access public
87 */ 122 */
88 function run(&$reporter) { 123 function run(&$reporter) {
89 - SimpleTest::setCurrent($this); 124 + $context = &SimpleTest::getContext();
  125 + $context->setTest($this);
  126 + $context->setReporter($reporter);
90 $this->_reporter = &$reporter; 127 $this->_reporter = &$reporter;
91 - $this->_reporter->paintCaseStart($this->getLabel());  
92 - foreach ($this->getTests() as $method) {  
93 - if ($this->_reporter->shouldInvoke($this->getLabel(), $method)) {  
94 - $invoker = &$this->_reporter->createInvoker($this->createInvoker());  
95 - $invoker->before($method);  
96 - $invoker->invoke($method);  
97 - $invoker->after($method); 128 + $reporter->paintCaseStart($this->getLabel());
  129 + $this->skip();
  130 + if (! $this->_should_skip) {
  131 + foreach ($this->getTests() as $method) {
  132 + if ($reporter->shouldInvoke($this->getLabel(), $method)) {
  133 + $invoker = &$this->_reporter->createInvoker($this->createInvoker());
  134 + $invoker->before($method);
  135 + $invoker->invoke($method);
  136 + $invoker->after($method);
  137 + }
98 } 138 }
99 } 139 }
100 - $this->_reporter->paintCaseEnd($this->getLabel()); 140 + $reporter->paintCaseEnd($this->getLabel());
101 unset($this->_reporter); 141 unset($this->_reporter);
102 return $reporter->getStatus(); 142 return $reporter->getStatus();
103 } 143 }
@@ -169,7 +209,7 @@ @@ -169,7 +209,7 @@
169 */ 209 */
170 function after($method) { 210 function after($method) {
171 for ($i = 0; $i < count($this->_observers); $i++) { 211 for ($i = 0; $i < count($this->_observers); $i++) {
172 - $this->_observers[$i]->atTestEnd($method); 212 + $this->_observers[$i]->atTestEnd($method, $this);
173 } 213 }
174 $this->_reporter->paintMethodEnd($method); 214 $this->_reporter->paintMethodEnd($method);
175 } 215 }
@@ -185,9 +225,7 @@ @@ -185,9 +225,7 @@
185 } 225 }
186 226
187 /** 227 /**
188 - * Sends a pass event with a message.  
189 - * @param string $message Message to send.  
190 - * @access public 228 + * @deprecated
191 */ 229 */
192 function pass($message = "Pass") { 230 function pass($message = "Pass") {
193 if (! isset($this->_reporter)) { 231 if (! isset($this->_reporter)) {
@@ -226,7 +264,7 @@ @@ -226,7 +264,7 @@
226 trigger_error('Can only make assertions within test methods'); 264 trigger_error('Can only make assertions within test methods');
227 } 265 }
228 $this->_reporter->paintError( 266 $this->_reporter->paintError(
229 - "Unexpected PHP error [$message] severity [$severity] in [$file] line [$line]"); 267 + "Unexpected PHP error [$message] severity [$severity] in [$file line $line]");
230 } 268 }
231 269
232 /** 270 /**
@@ -236,21 +274,11 @@ @@ -236,21 +274,11 @@
236 * @access public 274 * @access public
237 */ 275 */
238 function exception($exception) { 276 function exception($exception) {
239 - $this->_reporter->paintError(  
240 - 'Unexpected exception of type [' . get_class($exception) .  
241 - '] with message ['. $exception->getMessage() .  
242 - '] in ['. $exception->getFile() .  
243 - '] line [' . $exception->getLine() . ']'); 277 + $this->_reporter->paintException($exception);
244 } 278 }
245 279
246 /** 280 /**
247 - * Sends a user defined event to the test reporter.  
248 - * This is for small scale extension where  
249 - * both the test case and either the reporter or  
250 - * display are subclassed.  
251 - * @param string $type Type of event.  
252 - * @param mixed $payload Object or message to deliver.  
253 - * @access public 281 + * @deprecated
254 */ 282 */
255 function signal($type, &$payload) { 283 function signal($type, &$payload) {
256 if (! isset($this->_reporter)) { 284 if (! isset($this->_reporter)) {
@@ -260,15 +288,6 @@ @@ -260,15 +288,6 @@
260 } 288 }
261 289
262 /** 290 /**
263 - * Cancels any outstanding errors.  
264 - * @access public  
265 - */  
266 - function swallowErrors() {  
267 - $queue = &SimpleErrorQueue::instance();  
268 - $queue->clear();  
269 - }  
270 -  
271 - /**  
272 * Runs an expectation directly, for extending the 291 * Runs an expectation directly, for extending the
273 * tests with new expectation classes. 292 * tests with new expectation classes.
274 * @param SimpleExpectation $expectation Expectation subclass. 293 * @param SimpleExpectation $expectation Expectation subclass.
@@ -278,9 +297,15 @@ @@ -278,9 +297,15 @@
278 * @access public 297 * @access public
279 */ 298 */
280 function assert(&$expectation, $compare, $message = '%s') { 299 function assert(&$expectation, $compare, $message = '%s') {
281 - return $this->assertTrue(  
282 - $expectation->test($compare),  
283 - sprintf($message, $expectation->overlayMessage($compare))); 300 + if ($expectation->test($compare)) {
  301 + return $this->pass(sprintf(
  302 + $message,
  303 + $expectation->overlayMessage($compare, $this->_reporter->getDumper())));
  304 + } else {
  305 + return $this->fail(sprintf(
  306 + $message,
  307 + $expectation->overlayMessage($compare, $this->_reporter->getDumper())));
  308 + }
284 } 309 }
285 310
286 /** 311 /**
@@ -291,57 +316,14 @@ @@ -291,57 +316,14 @@
291 } 316 }
292 317
293 /** 318 /**
294 - * Called from within the test methods to register  
295 - * passes and failures.  
296 - * @param boolean $result Pass on true.  
297 - * @param string $message Message to display describing  
298 - * the test state.  
299 - * @return boolean True on pass  
300 - * @access public  
301 - */  
302 - function assertTrue($result, $message = false) {  
303 - if (! $message) {  
304 - $message = 'True assertion got ' . ($result ? 'True' : 'False');  
305 - }  
306 - if ($result) {  
307 - return $this->pass($message);  
308 - } else {  
309 - return $this->fail($message);  
310 - }  
311 - }  
312 -  
313 - /**  
314 - * Will be true on false and vice versa. False  
315 - * is the PHP definition of false, so that null,  
316 - * empty strings, zero and an empty array all count  
317 - * as false.  
318 - * @param boolean $result Pass on false.  
319 - * @param string $message Message to display.  
320 - * @return boolean True on pass  
321 - * @access public  
322 - */  
323 - function assertFalse($result, $message = false) {  
324 - if (! $message) {  
325 - $message = 'False assertion got ' . ($result ? 'True' : 'False');  
326 - }  
327 - return $this->assertTrue(! $result, $message);  
328 - }  
329 -  
330 - /**  
331 * Uses a stack trace to find the line of an assertion. 319 * Uses a stack trace to find the line of an assertion.
332 - * @param string $format String formatting.  
333 - * @param array $stack Stack frames top most first. Only  
334 - * needed if not using the PHP  
335 - * backtrace function.  
336 * @return string Line number of first assert* 320 * @return string Line number of first assert*
337 * method embedded in format string. 321 * method embedded in format string.
338 * @access public 322 * @access public
339 */ 323 */
340 - function getAssertionLine($stack = false) {  
341 - if ($stack === false) {  
342 - $stack = SimpleTestCompatibility::getStackTrace();  
343 - }  
344 - return SimpleDumper::getFormattedAssertionLine($stack); 324 + function getAssertionLine() {
  325 + $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip'));
  326 + return $trace->traceMethod();
345 } 327 }
346 328
347 /** 329 /**
@@ -354,7 +336,8 @@ @@ -354,7 +336,8 @@
354 * @access public 336 * @access public
355 */ 337 */
356 function dump($variable, $message = false) { 338 function dump($variable, $message = false) {
357 - $formatted = SimpleDumper::dump($variable); 339 + $dumper = $this->_reporter->getDumper();
  340 + $formatted = $dumper->dump($variable);
358 if ($message) { 341 if ($message) {
359 $formatted = $message . "\n" . $formatted; 342 $formatted = $message . "\n" . $formatted;
360 } 343 }
@@ -363,10 +346,7 @@ @@ -363,10 +346,7 @@
363 } 346 }
364 347
365 /** 348 /**
366 - * Dispatches a text message straight to the  
367 - * test suite. Useful for status bar displays.  
368 - * @param string $message Message to show.  
369 - * @access public 349 + * @deprecated
370 */ 350 */
371 function sendMessage($message) { 351 function sendMessage($message) {
372 $this->_reporter->PaintMessage($message); 352 $this->_reporter->PaintMessage($message);
@@ -390,7 +370,7 @@ @@ -390,7 +370,7 @@
390 * @package SimpleTest 370 * @package SimpleTest
391 * @subpackage UnitTester 371 * @subpackage UnitTester
392 */ 372 */
393 - class GroupTest { 373 + class TestSuite {
394 var $_label; 374 var $_label;
395 var $_test_cases; 375 var $_test_cases;
396 var $_old_track_errors; 376 var $_old_track_errors;
@@ -402,7 +382,7 @@ @@ -402,7 +382,7 @@
402 * of the test. 382 * of the test.
403 * @access public 383 * @access public
404 */ 384 */
405 - function GroupTest($label = false) { 385 + function TestSuite($label = false) {
406 $this->_label = $label ? $label : get_class($this); 386 $this->_label = $label ? $label : get_class($this);
407 $this->_test_cases = array(); 387 $this->_test_cases = array();
408 $this->_old_track_errors = ini_get('track_errors'); 388 $this->_old_track_errors = ini_get('track_errors');
@@ -440,7 +420,7 @@ @@ -440,7 +420,7 @@
440 * @access public 420 * @access public
441 */ 421 */
442 function addTestClass($class) { 422 function addTestClass($class) {
443 - if ($this->_getBaseTestCase($class) == 'grouptest') { 423 + if ($this->_getBaseTestCase($class) == 'testsuite' || $this->_getBaseTestCase($class) == 'grouptest') {
444 $this->_test_cases[] = &new $class(); 424 $this->_test_cases[] = &new $class();
445 } else { 425 } else {
446 $this->_test_cases[] = $class; 426 $this->_test_cases[] = $class;
@@ -457,12 +437,12 @@ @@ -457,12 +437,12 @@
457 function addTestFile($test_file) { 437 function addTestFile($test_file) {
458 $existing_classes = get_declared_classes(); 438 $existing_classes = get_declared_classes();
459 if ($error = $this->_requireWithError($test_file)) { 439 if ($error = $this->_requireWithError($test_file)) {
460 - $this->addTestCase(new BadGroupTest($test_file, $error)); 440 + $this->addTestCase(new BadTestSuite($test_file, $error));
461 return; 441 return;
462 } 442 }
463 $classes = $this->_selectRunnableTests($existing_classes, get_declared_classes()); 443 $classes = $this->_selectRunnableTests($existing_classes, get_declared_classes());
464 if (count($classes) == 0) { 444 if (count($classes) == 0) {
465 - $this->addTestCase(new BadGroupTest($test_file, "No runnable test cases in [$test_file]")); 445 + $this->addTestCase(new BadTestSuite($test_file, "No runnable test cases in [$test_file]"));
466 return; 446 return;
467 } 447 }
468 $group = &$this->_createGroupFromClasses($test_file, $classes); 448 $group = &$this->_createGroupFromClasses($test_file, $classes);
@@ -482,11 +462,14 @@ @@ -482,11 +462,14 @@
482 $error = isset($php_errormsg) ? $php_errormsg : false; 462 $error = isset($php_errormsg) ? $php_errormsg : false;
483 $this->_disableErrorReporting(); 463 $this->_disableErrorReporting();
484 $self_inflicted_errors = array( 464 $self_inflicted_errors = array(
485 - 'Assigning the return value of new by reference is deprecated',  
486 - 'var: Deprecated. Please use the public/private/protected modifiers');  
487 - if (in_array($error, $self_inflicted_errors)) {  
488 - return false;  
489 - } 465 + '/Assigning the return value of new by reference/i',
  466 + '/var: Deprecated/i',
  467 + '/Non-static method/i');
  468 + foreach ($self_inflicted_errors as $pattern) {
  469 + if (preg_match($pattern, $error)) {
  470 + return false;
  471 + }
  472 + }
490 return $error; 473 return $error;
491 } 474 }
492 475
@@ -548,13 +531,13 @@ @@ -548,13 +531,13 @@
548 * Builds a group test from a class list. 531 * Builds a group test from a class list.
549 * @param string $title Title of new group. 532 * @param string $title Title of new group.
550 * @param array $classes Test classes. 533 * @param array $classes Test classes.
551 - * @return GroupTest Group loaded with the new 534 + * @return TestSuite Group loaded with the new
552 * test cases. 535 * test cases.
553 * @access private 536 * @access private
554 */ 537 */
555 function &_createGroupFromClasses($title, $classes) { 538 function &_createGroupFromClasses($title, $classes) {
556 SimpleTest::ignoreParentsIfIgnored($classes); 539 SimpleTest::ignoreParentsIfIgnored($classes);
557 - $group = &new GroupTest($title); 540 + $group = &new TestSuite($title);
558 foreach ($classes as $class) { 541 foreach ($classes as $class) {
559 if (! SimpleTest::isIgnored($class)) { 542 if (! SimpleTest::isIgnored($class)) {
560 $group->addTestClass($class); 543 $group->addTestClass($class);
@@ -572,7 +555,7 @@ @@ -572,7 +555,7 @@
572 function _getBaseTestCase($class) { 555 function _getBaseTestCase($class) {
573 while ($class = get_parent_class($class)) { 556 while ($class = get_parent_class($class)) {
574 $class = strtolower($class); 557 $class = strtolower($class);
575 - if ($class == "simpletestcase" || $class == "grouptest") { 558 + if ($class == 'simpletestcase' || $class == 'testsuite' || $class == 'grouptest') {
576 return $class; 559 return $class;
577 } 560 }
578 } 561 }
@@ -603,6 +586,7 @@ @@ -603,6 +586,7 @@
603 $class = $this->_test_cases[$i]; 586 $class = $this->_test_cases[$i];
604 $test = &new $class(); 587 $test = &new $class();
605 $test->run($reporter); 588 $test->run($reporter);
  589 + unset($test);
606 } else { 590 } else {
607 $this->_test_cases[$i]->run($reporter); 591 $this->_test_cases[$i]->run($reporter);
608 } 592 }
@@ -628,6 +612,11 @@ @@ -628,6 +612,11 @@
628 return $count; 612 return $count;
629 } 613 }
630 } 614 }
  615 +
  616 + /**
  617 + * @deprecated
  618 + */
  619 + class GroupTest extends TestSuite { }
631 620
632 /** 621 /**
633 * This is a failing group test for when a test suite hasn't 622 * This is a failing group test for when a test suite hasn't
@@ -635,7 +624,7 @@ @@ -635,7 +624,7 @@
635 * @package SimpleTest 624 * @package SimpleTest
636 * @subpackage UnitTester 625 * @subpackage UnitTester
637 */ 626 */
638 - class BadGroupTest { 627 + class BadTestSuite {
639 var $_label; 628 var $_label;
640 var $_error; 629 var $_error;
641 630
@@ -645,7 +634,7 @@ @@ -645,7 +634,7 @@
645 * of the test. 634 * of the test.
646 * @access public 635 * @access public
647 */ 636 */
648 - function BadGroupTest($label, $error) { 637 + function BadTestSuite($label, $error) {
649 $this->_label = $label; 638 $this->_label = $label;
650 $this->_error = $error; 639 $this->_error = $error;
651 } 640 }
@@ -666,7 +655,7 @@ @@ -666,7 +655,7 @@
666 */ 655 */
667 function run(&$reporter) { 656 function run(&$reporter) {
668 $reporter->paintGroupStart($this->getLabel(), $this->getSize()); 657 $reporter->paintGroupStart($this->getLabel(), $this->getSize());
669 - $reporter->paintFail('Bad GroupTest [' . $this->getLabel() . 658 + $reporter->paintFail('Bad TestSuite [' . $this->getLabel() .
670 '] with error [' . $this->_error . ']'); 659 '] with error [' . $this->_error . ']');
671 $reporter->paintGroupEnd($this->getLabel()); 660 $reporter->paintGroupEnd($this->getLabel());
672 return $reporter->getStatus(); 661 return $reporter->getStatus();
@@ -681,4 +670,9 @@ @@ -681,4 +670,9 @@
681 return 0; 670 return 0;
682 } 671 }
683 } 672 }
684 -?> 673 +
  674 + /**
  675 + * @deprecated
  676 + */
  677 + class BadGroupTest extends BadTestSuite { }
  678 +?>
685 \ No newline at end of file 679 \ No newline at end of file
thirdparty/simpletest/simpletest/unit_tester.php
@@ -37,17 +37,44 @@ @@ -37,17 +37,44 @@
37 } 37 }
38 38
39 /** 39 /**
  40 + * Called from within the test methods to register
  41 + * passes and failures.
  42 + * @param boolean $result Pass on true.
  43 + * @param string $message Message to display describing
  44 + * the test state.
  45 + * @return boolean True on pass
  46 + * @access public
  47 + */
  48 + function assertTrue($result, $message = false) {
  49 + return $this->assert(new TrueExpectation(), $result, $message);
  50 + }
  51 +
  52 + /**
  53 + * Will be true on false and vice versa. False
  54 + * is the PHP definition of false, so that null,
  55 + * empty strings, zero and an empty array all count
  56 + * as false.
  57 + * @param boolean $result Pass on false.
  58 + * @param string $message Message to display.
  59 + * @return boolean True on pass
  60 + * @access public
  61 + */
  62 + function assertFalse($result, $message = '%s') {
  63 + return $this->assert(new FalseExpectation(), $result, $message);
  64 + }
  65 +
  66 + /**
40 * Will be true if the value is null. 67 * Will be true if the value is null.
41 * @param null $value Supposedly null value. 68 * @param null $value Supposedly null value.
42 * @param string $message Message to display. 69 * @param string $message Message to display.
43 * @return boolean True on pass 70 * @return boolean True on pass
44 * @access public 71 * @access public
45 */ 72 */
46 - function assertNull($value, $message = "%s") { 73 + function assertNull($value, $message = '%s') {
47 $dumper = &new SimpleDumper(); 74 $dumper = &new SimpleDumper();
48 $message = sprintf( 75 $message = sprintf(
49 $message, 76 $message,
50 - "[" . $dumper->describeValue($value) . "] should be null"); 77 + '[' . $dumper->describeValue($value) . '] should be null');
51 return $this->assertTrue(! isset($value), $message); 78 return $this->assertTrue(! isset($value), $message);
52 } 79 }
53 80
@@ -58,11 +85,11 @@ @@ -58,11 +85,11 @@
58 * @return boolean True on pass. 85 * @return boolean True on pass.
59 * @access public 86 * @access public
60 */ 87 */
61 - function assertNotNull($value, $message = "%s") { 88 + function assertNotNull($value, $message = '%s') {
62 $dumper = &new SimpleDumper(); 89 $dumper = &new SimpleDumper();
63 $message = sprintf( 90 $message = sprintf(
64 $message, 91 $message,
65 - "[" . $dumper->describeValue($value) . "] should not be null"); 92 + '[' . $dumper->describeValue($value) . '] should not be null');
66 return $this->assertTrue(isset($value), $message); 93 return $this->assertTrue(isset($value), $message);
67 } 94 }
68 95
@@ -76,7 +103,7 @@ @@ -76,7 +103,7 @@
76 * @return boolean True on pass. 103 * @return boolean True on pass.
77 * @access public 104 * @access public
78 */ 105 */
79 - function assertIsA($object, $type, $message = "%s") { 106 + function assertIsA($object, $type, $message = '%s') {
80 return $this->assert( 107 return $this->assert(
81 new IsAExpectation($type), 108 new IsAExpectation($type),
82 $object, 109 $object,
@@ -93,7 +120,7 @@ @@ -93,7 +120,7 @@
93 * @return boolean True on pass. 120 * @return boolean True on pass.
94 * @access public 121 * @access public
95 */ 122 */
96 - function assertNotA($object, $type, $message = "%s") { 123 + function assertNotA($object, $type, $message = '%s') {
97 return $this->assert( 124 return $this->assert(
98 new NotAExpectation($type), 125 new NotAExpectation($type),
99 $object, 126 $object,
@@ -109,7 +136,7 @@ @@ -109,7 +136,7 @@
109 * @return boolean True on pass 136 * @return boolean True on pass
110 * @access public 137 * @access public
111 */ 138 */
112 - function assertEqual($first, $second, $message = "%s") { 139 + function assertEqual($first, $second, $message = '%s') {
113 return $this->assert( 140 return $this->assert(
114 new EqualExpectation($first), 141 new EqualExpectation($first),
115 $second, 142 $second,
@@ -125,7 +152,7 @@ @@ -125,7 +152,7 @@
125 * @return boolean True on pass 152 * @return boolean True on pass
126 * @access public 153 * @access public
127 */ 154 */
128 - function assertNotEqual($first, $second, $message = "%s") { 155 + function assertNotEqual($first, $second, $message = '%s') {
129 return $this->assert( 156 return $this->assert(
130 new NotEqualExpectation($first), 157 new NotEqualExpectation($first),
131 $second, 158 $second,
@@ -142,7 +169,7 @@ @@ -142,7 +169,7 @@
142 * @return boolean True on pass 169 * @return boolean True on pass
143 * @access public 170 * @access public
144 */ 171 */
145 - function assertWithinMargin($first, $second, $margin, $message = "%s") { 172 + function assertWithinMargin($first, $second, $margin, $message = '%s') {
146 return $this->assert( 173 return $this->assert(
147 new WithinMarginExpectation($first, $margin), 174 new WithinMarginExpectation($first, $margin),
148 $second, 175 $second,
@@ -159,7 +186,7 @@ @@ -159,7 +186,7 @@
159 * @return boolean True on pass 186 * @return boolean True on pass
160 * @access public 187 * @access public
161 */ 188 */
162 - function assertOutsideMargin($first, $second, $margin, $message = "%s") { 189 + function assertOutsideMargin($first, $second, $margin, $message = '%s') {
163 return $this->assert( 190 return $this->assert(
164 new OutsideMarginExpectation($first, $margin), 191 new OutsideMarginExpectation($first, $margin),
165 $second, 192 $second,
@@ -175,7 +202,7 @@ @@ -175,7 +202,7 @@
175 * @return boolean True on pass 202 * @return boolean True on pass
176 * @access public 203 * @access public
177 */ 204 */
178 - function assertIdentical($first, $second, $message = "%s") { 205 + function assertIdentical($first, $second, $message = '%s') {
179 return $this->assert( 206 return $this->assert(
180 new IdenticalExpectation($first), 207 new IdenticalExpectation($first),
181 $second, 208 $second,
@@ -191,7 +218,7 @@ @@ -191,7 +218,7 @@
191 * @return boolean True on pass 218 * @return boolean True on pass
192 * @access public 219 * @access public
193 */ 220 */
194 - function assertNotIdentical($first, $second, $message = "%s") { 221 + function assertNotIdentical($first, $second, $message = '%s') {
195 return $this->assert( 222 return $this->assert(
196 new NotIdenticalExpectation($first), 223 new NotIdenticalExpectation($first),
197 $second, 224 $second,
@@ -207,13 +234,13 @@ @@ -207,13 +234,13 @@
207 * @return boolean True on pass 234 * @return boolean True on pass
208 * @access public 235 * @access public
209 */ 236 */
210 - function assertReference(&$first, &$second, $message = "%s") { 237 + function assertReference(&$first, &$second, $message = '%s') {
211 $dumper = &new SimpleDumper(); 238 $dumper = &new SimpleDumper();
212 $message = sprintf( 239 $message = sprintf(
213 $message, 240 $message,
214 - "[" . $dumper->describeValue($first) .  
215 - "] and [" . $dumper->describeValue($second) .  
216 - "] should reference the same object"); 241 + '[' . $dumper->describeValue($first) .
  242 + '] and [' . $dumper->describeValue($second) .
  243 + '] should reference the same object');
217 return $this->assertTrue( 244 return $this->assertTrue(
218 SimpleTestCompatibility::isReference($first, $second), 245 SimpleTestCompatibility::isReference($first, $second),
219 $message); 246 $message);
@@ -229,13 +256,13 @@ @@ -229,13 +256,13 @@
229 * @return boolean True on pass 256 * @return boolean True on pass
230 * @access public 257 * @access public
231 */ 258 */
232 - function assertClone(&$first, &$second, $message = "%s") { 259 + function assertClone(&$first, &$second, $message = '%s') {
233 $dumper = &new SimpleDumper(); 260 $dumper = &new SimpleDumper();
234 $message = sprintf( 261 $message = sprintf(
235 $message, 262 $message,
236 - "[" . $dumper->describeValue($first) .  
237 - "] and [" . $dumper->describeValue($second) .  
238 - "] should not be the same object"); 263 + '[' . $dumper->describeValue($first) .
  264 + '] and [' . $dumper->describeValue($second) .
  265 + '] should not be the same object');
239 $identical = &new IdenticalExpectation($first); 266 $identical = &new IdenticalExpectation($first);
240 return $this->assertTrue( 267 return $this->assertTrue(
241 $identical->test($second) && 268 $identical->test($second) &&
@@ -268,7 +295,7 @@ @@ -268,7 +295,7 @@
268 * @return boolean True on pass 295 * @return boolean True on pass
269 * @access public 296 * @access public
270 */ 297 */
271 - function assertPattern($pattern, $subject, $message = "%s") { 298 + function assertPattern($pattern, $subject, $message = '%s') {
272 return $this->assert( 299 return $this->assert(
273 new PatternExpectation($pattern), 300 new PatternExpectation($pattern),
274 $subject, 301 $subject,
@@ -278,7 +305,7 @@ @@ -278,7 +305,7 @@
278 /** 305 /**
279 * @deprecated 306 * @deprecated
280 */ 307 */
281 - function assertWantedPattern($pattern, $subject, $message = "%s") { 308 + function assertWantedPattern($pattern, $subject, $message = '%s') {
282 return $this->assertPattern($pattern, $subject, $message); 309 return $this->assertPattern($pattern, $subject, $message);
283 } 310 }
284 311
@@ -292,7 +319,7 @@ @@ -292,7 +319,7 @@
292 * @return boolean True on pass 319 * @return boolean True on pass
293 * @access public 320 * @access public
294 */ 321 */
295 - function assertNoPattern($pattern, $subject, $message = "%s") { 322 + function assertNoPattern($pattern, $subject, $message = '%s') {
296 return $this->assert( 323 return $this->assert(
297 new NoPatternExpectation($pattern), 324 new NoPatternExpectation($pattern),
298 $subject, 325 $subject,
@@ -302,50 +329,63 @@ @@ -302,50 +329,63 @@
302 /** 329 /**
303 * @deprecated 330 * @deprecated
304 */ 331 */
305 - function assertNoUnwantedPattern($pattern, $subject, $message = "%s") { 332 + function assertNoUnwantedPattern($pattern, $subject, $message = '%s') {
306 return $this->assertNoPattern($pattern, $subject, $message); 333 return $this->assertNoPattern($pattern, $subject, $message);
307 } 334 }
308 335
309 /** 336 /**
310 - * Confirms that no errors have occoured so  
311 - * far in the test method.  
312 - * @param string $message Message to display.  
313 - * @return boolean True on pass 337 + * @deprecated
  338 + */
  339 + function swallowErrors() {
  340 + $context = &SimpleTest::getContext();
  341 + $queue = &$context->get('SimpleErrorQueue');
  342 + $queue->clear();
  343 + }
  344 +
  345 + /**
  346 + * @deprecated
  347 + */
  348 + function assertNoErrors($message = '%s') {
  349 + $context = &SimpleTest::getContext();
  350 + $queue = &$context->get('SimpleErrorQueue');
  351 + return $queue->assertNoErrors($message);
  352 + }
  353 +
  354 + /**
  355 + * @deprecated
  356 + */
  357 + function assertError($expected = false, $message = '%s') {
  358 + $context = &SimpleTest::getContext();
  359 + $queue = &$context->get('SimpleErrorQueue');
  360 + return $queue->assertError($this->_coerceExpectation($expected), $message);
  361 + }
  362 +
  363 + /**
  364 + * Prepares for an error. If the error mismatches it
  365 + * passes through, otherwise it is swallowed. Any
  366 + * left over errors trigger failures.
  367 + * @param SimpleExpectation/string $expected The error to match.
  368 + * @param string $message Message on failure.
314 * @access public 369 * @access public
315 */ 370 */
316 - function assertNoErrors($message = "%s") {  
317 - $queue = &SimpleErrorQueue::instance();  
318 - return $this->assertTrue(  
319 - $queue->isEmpty(),  
320 - sprintf($message, "Should be no errors")); 371 + function expectError($expected = false, $message = '%s') {
  372 + $context = &SimpleTest::getContext();
  373 + $queue = &$context->get('SimpleErrorQueue');
  374 + $queue->expectError($this->_coerceExpectation($expected), $message);
321 } 375 }
322 376
323 /** 377 /**
324 - * Confirms that an error has occoured and  
325 - * optionally that the error text matches exactly.  
326 - * @param string $expected Expected error text or  
327 - * false for no check.  
328 - * @param string $message Message to display.  
329 - * @return boolean True on pass 378 + * Prepares for an exception. If the error mismatches it
  379 + * passes through, otherwise it is swallowed. Any
  380 + * left over errors trigger failures.
  381 + * @param SimpleExpectation/Exception $expected The error to match.
  382 + * @param string $message Message on failure.
330 * @access public 383 * @access public
331 */ 384 */
332 - function assertError($expected = false, $message = "%s") {  
333 - $queue = &SimpleErrorQueue::instance();  
334 - if ($queue->isEmpty()) {  
335 - $this->fail(sprintf($message, "Expected error not found"));  
336 - return;  
337 - }  
338 - list($severity, $content, $file, $line, $globals) = $queue->extract();  
339 - $severity = SimpleErrorQueue::getSeverityAsString($severity);  
340 - if (! $expected) {  
341 - return $this->pass(  
342 - "Captured a PHP error of [$content] severity [$severity] in [$file] line [$line] -> %s");  
343 - }  
344 - $expected = $this->_coerceToExpectation($expected);  
345 - return $this->assert(  
346 - $expected,  
347 - $content,  
348 - "Expected PHP error [$content] severity [$severity] in [$file] line [$line] -> %s"); 385 + function expectException($expected = false, $message = '%s') {
  386 + $context = &SimpleTest::getContext();
  387 + $queue = &$context->get('SimpleExceptionTrap');
  388 + $queue->expectException($expected, $message . $this->getAssertionLine());
349 } 389 }
350 390
351 /** 391 /**
@@ -356,18 +396,24 @@ @@ -356,18 +396,24 @@
356 * @return SimpleExpectation Expectation object. 396 * @return SimpleExpectation Expectation object.
357 * @access private 397 * @access private
358 */ 398 */
359 - function _coerceToExpectation($expected) { 399 + function _coerceExpectation($expected) {
  400 + if ($expected == false) {
  401 + return new AnythingExpectation();
  402 + }
360 if (SimpleTestCompatibility::isA($expected, 'SimpleExpectation')) { 403 if (SimpleTestCompatibility::isA($expected, 'SimpleExpectation')) {
361 return $expected; 404 return $expected;
362 } 405 }
  406 + if(is_string($expected)) {
  407 + $expected = str_replace('%', '%%', $expected);
  408 + }
363 return new EqualExpectation($expected); 409 return new EqualExpectation($expected);
364 } 410 }
365 411
366 /** 412 /**
367 * @deprecated 413 * @deprecated
368 */ 414 */
369 - function assertErrorPattern($pattern, $message = "%s") { 415 + function assertErrorPattern($pattern, $message = '%s') {
370 return $this->assertError(new PatternExpectation($pattern), $message); 416 return $this->assertError(new PatternExpectation($pattern), $message);
371 } 417 }
372 } 418 }
373 -?> 419 -?>
  420 +?>
374 \ No newline at end of file 421 \ No newline at end of file
thirdparty/simpletest/simpletest/url.php
@@ -507,8 +507,8 @@ @@ -507,8 +507,8 @@
507 * @access public 507 * @access public
508 */ 508 */
509 function normalisePath($path) { 509 function normalisePath($path) {
510 - $path = preg_replace('|/[^/]+/\.\./|', '/', $path);  
511 - return preg_replace('|/\./|', '/', $path); 510 + $path = preg_replace('|/\./|', '/', $path);
  511 + return preg_replace('|/[^/]+/\.\./|', '/', $path);
512 } 512 }
513 513
514 /** 514 /**
thirdparty/simpletest/simpletest/web_tester.php
@@ -120,8 +120,8 @@ @@ -120,8 +120,8 @@
120 } else { 120 } else {
121 return "Field expectation [" . $dumper->describeValue($this->_value) . 121 return "Field expectation [" . $dumper->describeValue($this->_value) .
122 "] fails with [" . 122 "] fails with [" .
123 - $this->_dumper->describeValue($compare) . "] " .  
124 - $this->_dumper->describeDifference($this->_value, $compare); 123 + $dumper->describeValue($compare) . "] " .
  124 + $dumper->describeDifference($this->_value, $compare);
125 } 125 }
126 } 126 }
127 } 127 }
@@ -242,7 +242,7 @@ @@ -242,7 +242,7 @@
242 */ 242 */
243 function testMessage($compare) { 243 function testMessage($compare) {
244 if (SimpleExpectation::isExpectation($this->_expected_value)) { 244 if (SimpleExpectation::isExpectation($this->_expected_value)) {
245 - $message = $this->_expected_value->testMessage($compare); 245 + $message = $this->_expected_value->overlayMessage($compare, $this->_getDumper());
246 } else { 246 } else {
247 $message = $this->_expected_header . 247 $message = $this->_expected_header .
248 ($this->_expected_value ? ': ' . $this->_expected_value : ''); 248 ($this->_expected_value ? ': ' . $this->_expected_value : '');
@@ -784,7 +784,7 @@ @@ -784,7 +784,7 @@
784 * @param string $expiry Expiry date. 784 * @param string $expiry Expiry date.
785 * @access public 785 * @access public
786 */ 786 */
787 - function setCookie($name, $value, $host = false, $path = "/", $expiry = false) { 787 + function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
788 $this->_browser->setCookie($name, $value, $host, $path, $expiry); 788 $this->_browser->setCookie($name, $value, $host, $path, $expiry);
789 } 789 }
790 790
@@ -841,6 +841,18 @@ @@ -841,6 +841,18 @@
841 } 841 }
842 842
843 /** 843 /**
  844 + * Checks for a click target.
  845 + * @param string $label Visible text or alt text.
  846 + * @return boolean True if click target.
  847 + * @access public
  848 + */
  849 + function assertClickable($label, $message = '%s') {
  850 + return $this->assertTrue(
  851 + $this->_browser->isClickable($label),
  852 + sprintf($message, "Click target [$label] should exist"));
  853 + }
  854 +
  855 + /**
844 * Clicks the submit button by label. The owning 856 * Clicks the submit button by label. The owning
845 * form will be submitted by this. 857 * form will be submitted by this.
846 * @param string $label Button label. An unlabeled 858 * @param string $label Button label. An unlabeled
@@ -881,6 +893,18 @@ @@ -881,6 +893,18 @@
881 } 893 }
882 894
883 /** 895 /**
  896 + * Checks for a valid button label.
  897 + * @param string $label Visible text.
  898 + * @return boolean True if click target.
  899 + * @access public
  900 + */
  901 + function assertSubmit($label, $message = '%s') {
  902 + return $this->assertTrue(
  903 + $this->_browser->isSubmit($label),
  904 + sprintf($message, "Submit button [$label] should exist"));
  905 + }
  906 +
  907 + /**
884 * Clicks the submit image by some kind of label. Usually 908 * Clicks the submit image by some kind of label. Usually
885 * the alt tag or the nearest equivalent. The owning 909 * the alt tag or the nearest equivalent. The owning
886 * form will be submitted by this. Clicking outside of 910 * form will be submitted by this. Clicking outside of
@@ -934,6 +958,18 @@ @@ -934,6 +958,18 @@
934 } 958 }
935 959
936 /** 960 /**
  961 + * Checks for a valid image with atht alt text or title.
  962 + * @param string $label Visible text.
  963 + * @return boolean True if click target.
  964 + * @access public
  965 + */
  966 + function assertImage($label, $message = '%s') {
  967 + return $this->assertTrue(
  968 + $this->_browser->isImage($label),
  969 + sprintf($message, "Image with text [$label] should exist"));
  970 + }
  971 +
  972 + /**
937 * Submits a form by the ID. 973 * Submits a form by the ID.
938 * @param string $id Form ID. No button information 974 * @param string $id Form ID. No button information
939 * is submitted this way. 975 * is submitted this way.
@@ -969,52 +1005,24 @@ @@ -969,52 +1005,24 @@
969 } 1005 }
970 1006
971 /** 1007 /**
972 - * Will trigger a pass if the two parameters have  
973 - * the same value only. Otherwise a fail. This  
974 - * is for testing hand extracted text, etc.  
975 - * @param mixed $first Value to compare.  
976 - * @param mixed $second Value to compare.  
977 - * @param string $message Message to display.  
978 - * @return boolean True on pass  
979 - * @access public  
980 - */  
981 - function assertEqual($first, $second, $message = "%s") {  
982 - return $this->assert(  
983 - new EqualExpectation($first),  
984 - $second,  
985 - $message);  
986 - }  
987 -  
988 - /**  
989 - * Will trigger a pass if the two parameters have  
990 - * a different value. Otherwise a fail. This  
991 - * is for testing hand extracted text, etc.  
992 - * @param mixed $first Value to compare.  
993 - * @param mixed $second Value to compare.  
994 - * @param string $message Message to display.  
995 - * @return boolean True on pass  
996 - * @access public  
997 - */  
998 - function assertNotEqual($first, $second, $message = "%s") {  
999 - return $this->assert(  
1000 - new NotEqualExpectation($first),  
1001 - $second,  
1002 - $message);  
1003 - }  
1004 -  
1005 - /**  
1006 * Tests for the presence of a link label. Match is 1008 * Tests for the presence of a link label. Match is
1007 * case insensitive with normalised space. 1009 * case insensitive with normalised space.
1008 * @param string $label Text between the anchor tags. 1010 * @param string $label Text between the anchor tags.
  1011 + * @param mixed $expected Expected URL or expectation object.
1009 * @param string $message Message to display. Default 1012 * @param string $message Message to display. Default
1010 * can be embedded with %s. 1013 * can be embedded with %s.
1011 * @return boolean True if link present. 1014 * @return boolean True if link present.
1012 * @access public 1015 * @access public
1013 */ 1016 */
1014 - function assertLink($label, $message = "%s") {  
1015 - return $this->assertTrue(  
1016 - $this->_browser->isLink($label),  
1017 - sprintf($message, "Link [$label] should exist")); 1017 + function assertLink($label, $expected = true, $message = '%s') {
  1018 + $url = $this->_browser->getLink($label);
  1019 + if ($expected === true) {
  1020 + return $this->assertTrue($url !== false, sprintf($message, "Link [$label] should exist"));
  1021 + }
  1022 + if (! SimpleExpectation::isExpectation($expected)) {
  1023 + $expected = new IdenticalExpectation($expected);
  1024 + }
  1025 + return $this->assert($expected, $url->asString(), sprintf($message, "Link [$label] should match"));
1018 } 1026 }
1019 1027
1020 /** 1028 /**
@@ -1027,24 +1035,30 @@ @@ -1027,24 +1035,30 @@
1027 * @return boolean True if link missing. 1035 * @return boolean True if link missing.
1028 * @access public 1036 * @access public
1029 */ 1037 */
1030 - function assertNoLink($label, $message = "%s") {  
1031 - return $this->assertFalse(  
1032 - $this->_browser->isLink($label), 1038 + function assertNoLink($label, $message = '%s') {
  1039 + return $this->assertTrue(
  1040 + $this->_browser->getLink($label) === false,
1033 sprintf($message, "Link [$label] should not exist")); 1041 sprintf($message, "Link [$label] should not exist"));
1034 } 1042 }
1035 1043
1036 /** 1044 /**
1037 * Tests for the presence of a link id attribute. 1045 * Tests for the presence of a link id attribute.
1038 * @param string $id Id attribute value. 1046 * @param string $id Id attribute value.
  1047 + * @param mixed $expected Expected URL or expectation object.
1039 * @param string $message Message to display. Default 1048 * @param string $message Message to display. Default
1040 * can be embedded with %s. 1049 * can be embedded with %s.
1041 * @return boolean True if link present. 1050 * @return boolean True if link present.
1042 * @access public 1051 * @access public
1043 */ 1052 */
1044 - function assertLinkById($id, $message = "%s") {  
1045 - return $this->assertTrue(  
1046 - $this->_browser->isLinkById($id),  
1047 - sprintf($message, "Link ID [$id] should exist")); 1053 + function assertLinkById($id, $expected = true, $message = '%s') {
  1054 + $url = $this->_browser->getLinkById($id);
  1055 + if ($expected === true) {
  1056 + return $this->assertTrue($url !== false, sprintf($message, "Link ID [$id] should exist"));
  1057 + }
  1058 + if (! SimpleExpectation::isExpectation($expected)) {
  1059 + $expected = new IdenticalExpectation($expected);
  1060 + }
  1061 + return $this->assert($expected, $url->asString(), sprintf($message, "Link ID [$id] should match"));
1048 } 1062 }
1049 1063
1050 /** 1064 /**
@@ -1056,9 +1070,9 @@ @@ -1056,9 +1070,9 @@
1056 * @return boolean True if link missing. 1070 * @return boolean True if link missing.
1057 * @access public 1071 * @access public
1058 */ 1072 */
1059 - function assertNoLinkById($id, $message = "%s") {  
1060 - return $this->assertFalse(  
1061 - $this->_browser->isLinkById($id), 1073 + function assertNoLinkById($id, $message = '%s') {
  1074 + return $this->assertTrue(
  1075 + $this->_browser->getLinkById($id) === false,
1062 sprintf($message, "Link ID [$id] should not exist")); 1076 sprintf($message, "Link ID [$id] should not exist"));
1063 } 1077 }
1064 1078
@@ -1313,9 +1327,9 @@ @@ -1313,9 +1327,9 @@
1313 1327
1314 /** 1328 /**
1315 * Tests the text between the title tags. 1329 * Tests the text between the title tags.
1316 - * @param string $title Expected title.  
1317 - * @param string $message Message to display.  
1318 - * @return boolean True if pass. 1330 + * @param string/SimpleExpectation $title Expected title.
  1331 + * @param string $message Message to display.
  1332 + * @return boolean True if pass.
1319 * @access public 1333 * @access public
1320 */ 1334 */
1321 function assertTitle($title = false, $message = '%s') { 1335 function assertTitle($title = false, $message = '%s') {
@@ -1451,5 +1465,77 @@ @@ -1451,5 +1465,77 @@
1451 $this->getCookie($name) === false, 1465 $this->getCookie($name) === false,
1452 sprintf($message, "Not expecting cookie [$name]")); 1466 sprintf($message, "Not expecting cookie [$name]"));
1453 } 1467 }
  1468 +
  1469 + /**
  1470 + * Called from within the test methods to register
  1471 + * passes and failures.
  1472 + * @param boolean $result Pass on true.
  1473 + * @param string $message Message to display describing
  1474 + * the test state.
  1475 + * @return boolean True on pass
  1476 + * @access public
  1477 + */
  1478 + function assertTrue($result, $message = false) {
  1479 + return $this->assert(new TrueExpectation(), $result, $message);
  1480 + }
  1481 +
  1482 + /**
  1483 + * Will be true on false and vice versa. False
  1484 + * is the PHP definition of false, so that null,
  1485 + * empty strings, zero and an empty array all count
  1486 + * as false.
  1487 + * @param boolean $result Pass on false.
  1488 + * @param string $message Message to display.
  1489 + * @return boolean True on pass
  1490 + * @access public
  1491 + */
  1492 + function assertFalse($result, $message = '%s') {
  1493 + return $this->assert(new FalseExpectation(), $result, $message);
  1494 + }
  1495 +
  1496 + /**
  1497 + * Will trigger a pass if the two parameters have
  1498 + * the same value only. Otherwise a fail. This
  1499 + * is for testing hand extracted text, etc.
  1500 + * @param mixed $first Value to compare.
  1501 + * @param mixed $second Value to compare.
  1502 + * @param string $message Message to display.
  1503 + * @return boolean True on pass
  1504 + * @access public
  1505 + */
  1506 + function assertEqual($first, $second, $message = '%s') {
  1507 + return $this->assert(
  1508 + new EqualExpectation($first),
  1509 + $second,
  1510 + $message);
  1511 + }
  1512 +
  1513 + /**
  1514 + * Will trigger a pass if the two parameters have
  1515 + * a different value. Otherwise a fail. This
  1516 + * is for testing hand extracted text, etc.
  1517 + * @param mixed $first Value to compare.
  1518 + * @param mixed $second Value to compare.
  1519 + * @param string $message Message to display.
  1520 + * @return boolean True on pass
  1521 + * @access public
  1522 + */
  1523 + function assertNotEqual($first, $second, $message = '%s') {
  1524 + return $this->assert(
  1525 + new NotEqualExpectation($first),
  1526 + $second,
  1527 + $message);
  1528 + }
  1529 +
  1530 + /**
  1531 + * Uses a stack trace to find the line of an assertion.
  1532 + * @return string Line number of first assert*
  1533 + * method embedded in format string.
  1534 + * @access public
  1535 + */
  1536 + function getAssertionLine() {
  1537 + $trace = new SimpleStackTrace(array('assert', 'click', 'pass', 'fail'));
  1538 + return $trace->traceMethod();
  1539 + }
1454 } 1540 }
1455 ?> 1541 ?>
1456 \ No newline at end of file 1542 \ No newline at end of file
thirdparty/simpletest/simpletest/xml.php
@@ -23,7 +23,9 @@ @@ -23,7 +23,9 @@
23 var $_namespace; 23 var $_namespace;
24 24
25 /** 25 /**
26 - * Does nothing yet. 26 + * Sets up indentation and namespace.
  27 + * @param string $namespace Namespace to add to each tag.
  28 + * @param string $indent Indenting to add on each nesting.
27 * @access public 29 * @access public
28 */ 30 */
29 function XmlReporter($namespace = false, $indent = ' ') { 31 function XmlReporter($namespace = false, $indent = ' ') {
@@ -140,8 +142,8 @@ @@ -140,8 +142,8 @@
140 } 142 }
141 143
142 /** 144 /**
143 - * Increments the pass count.  
144 - * @param string $message Message is ignored. 145 + * Paints pass as XML.
  146 + * @param string $message Message to encode.
145 * @access public 147 * @access public
146 */ 148 */
147 function paintPass($message) { 149 function paintPass($message) {
@@ -153,8 +155,8 @@ @@ -153,8 +155,8 @@
153 } 155 }
154 156
155 /** 157 /**
156 - * Increments the fail count.  
157 - * @param string $message Message is ignored. 158 + * Paints failure as XML.
  159 + * @param string $message Message to encode.
158 * @access public 160 * @access public
159 */ 161 */
160 function paintFail($message) { 162 function paintFail($message) {
@@ -166,10 +168,9 @@ @@ -166,10 +168,9 @@
166 } 168 }
167 169
168 /** 170 /**
169 - * Paints a PHP error or exception.  
170 - * @param string $message Message is ignored. 171 + * Paints error as XML.
  172 + * @param string $message Message to encode.
171 * @access public 173 * @access public
172 - * @abstract  
173 */ 174 */
174 function paintError($message) { 175 function paintError($message) {
175 parent::paintError($message); 176 parent::paintError($message);
@@ -180,6 +181,36 @@ @@ -180,6 +181,36 @@
180 } 181 }
181 182
182 /** 183 /**
  184 + * Paints exception as XML.
  185 + * @param Exception $exception Exception to encode.
  186 + * @access public
  187 + */
  188 + function paintException($exception) {
  189 + parent::paintException($exception);
  190 + print $this->_getIndent(1);
  191 + print "<" . $this->_namespace . "exception>";
  192 + $message = 'Unexpected exception of type [' . get_class($exception) .
  193 + '] with message ['. $exception->getMessage() .
  194 + '] in ['. $exception->getFile() .
  195 + ' line ' . $exception->getLine() . ']';
  196 + print $this->toParsedXml($message);
  197 + print "</" . $this->_namespace . "exception>\n";
  198 + }
  199 +
  200 + /**
  201 + * Paints the skipping message and tag.
  202 + * @param string $message Text to display in skip tag.
  203 + * @access public
  204 + */
  205 + function paintSkip($message) {
  206 + parent::paintSkip($message);
  207 + print $this->_getIndent(1);
  208 + print "<" . $this->_namespace . "skip>";
  209 + print $this->toParsedXml($message);
  210 + print "</" . $this->_namespace . "skip>\n";
  211 + }
  212 +
  213 + /**
183 * Paints a simple supplementary message. 214 * Paints a simple supplementary message.
184 * @param string $message Text to display. 215 * @param string $message Text to display.
185 * @access public 216 * @access public
@@ -531,7 +562,7 @@ @@ -531,7 +562,7 @@
531 */ 562 */
532 function _isLeaf($tag) { 563 function _isLeaf($tag) {
533 return in_array($tag, array( 564 return in_array($tag, array(
534 - 'NAME', 'PASS', 'FAIL', 'EXCEPTION', 'MESSAGE', 'FORMATTED', 'SIGNAL')); 565 + 'NAME', 'PASS', 'FAIL', 'EXCEPTION', 'SKIP', 'MESSAGE', 'FORMATTED', 'SIGNAL'));
535 } 566 }
536 567
537 /** 568 /**
@@ -578,6 +609,8 @@ @@ -578,6 +609,8 @@
578 $this->_listener->paintFail($this->_content); 609 $this->_listener->paintFail($this->_content);
579 } elseif ($tag == 'EXCEPTION') { 610 } elseif ($tag == 'EXCEPTION') {
580 $this->_listener->paintError($this->_content); 611 $this->_listener->paintError($this->_content);
  612 + } elseif ($tag == 'SKIP') {
  613 + $this->_listener->paintSkip($this->_content);
581 } elseif ($tag == 'SIGNAL') { 614 } elseif ($tag == 'SIGNAL') {
582 $this->_listener->paintSignal( 615 $this->_listener->paintSignal(
583 $this->_attributes['TYPE'], 616 $this->_attributes['TYPE'],