mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
(merged from branches/roa. use "svn log -c <changeset> -g <module-svn-path>" for detailed commit message)
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@60228 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
8fd1a33d84
commit
0a8f2a67f6
@ -162,12 +162,12 @@ class RestfulServer extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$obj = $this->search($className, $this->request->getVars(), $sort, $limit);
|
|
||||||
// show empty serialized result when no records are present
|
|
||||||
if(!$obj) $obj = new DataObjectSet();
|
|
||||||
if(!singleton($className)->stat('api_access')) {
|
if(!singleton($className)->stat('api_access')) {
|
||||||
return $this->permissionFailure();
|
return $this->permissionFailure();
|
||||||
}
|
}
|
||||||
|
$obj = $this->search($className, $this->request->getVars(), $sort, $limit);
|
||||||
|
// show empty serialized result when no records are present
|
||||||
|
if(!$obj) $obj = new DataObjectSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
if($obj instanceof DataObjectSet) return $formatter->convertDataObjectSet($obj);
|
if($obj instanceof DataObjectSet) return $formatter->convertDataObjectSet($obj);
|
||||||
@ -187,7 +187,11 @@ class RestfulServer extends Controller {
|
|||||||
* @return DataObjectSet
|
* @return DataObjectSet
|
||||||
*/
|
*/
|
||||||
protected function search($className, $params = null, $sort = null, $limit = null, $existingQuery = null) {
|
protected function search($className, $params = null, $sort = null, $limit = null, $existingQuery = null) {
|
||||||
$searchContext = singleton($className)->getDefaultSearchContext();
|
if(singleton($className)->hasMethod('getRestfulSearchContext')) {
|
||||||
|
$searchContext = singleton($className)->{'getRestfulSearchContext'}();
|
||||||
|
} else {
|
||||||
|
$searchContext = singleton($className)->getDefaultSearchContext();
|
||||||
|
}
|
||||||
$query = $searchContext->getQuery($params, $sort, $limit, $existingQuery);
|
$query = $searchContext->getQuery($params, $sort, $limit, $existingQuery);
|
||||||
|
|
||||||
return singleton($className)->buildDataObjectSet($query->execute());
|
return singleton($className)->buildDataObjectSet($query->execute());
|
||||||
|
@ -51,6 +51,9 @@ if( preg_match( '/(test\.totallydigital\.co\.nz|dev\.totallydigital\.co\.nz\/tes
|
|||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set request method (doesn't allow POST through cli)
|
||||||
|
$_SERVER['REQUEST_METHOD'] = "GET";
|
||||||
|
|
||||||
$baseURL = dirname( dirname( $_SERVER['SCRIPT_NAME'] ) );
|
$baseURL = dirname( dirname( $_SERVER['SCRIPT_NAME'] ) );
|
||||||
|
|
||||||
if($_REQUEST && get_magic_quotes_gpc()) {
|
if($_REQUEST && get_magic_quotes_gpc()) {
|
||||||
|
@ -1081,8 +1081,9 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
|||||||
if ($this->many_many()) {
|
if ($this->many_many()) {
|
||||||
foreach($this->many_many() as $relationship => $component) {
|
foreach($this->many_many() as $relationship => $component) {
|
||||||
$relationshipFields = singleton($component)->summary_fields();
|
$relationshipFields = singleton($component)->summary_fields();
|
||||||
|
$filterWhere = $this->getManyManyFilter($relationship, $component);
|
||||||
$filterJoin = $this->getManyManyJoin($relationship, $component);
|
$filterJoin = $this->getManyManyJoin($relationship, $component);
|
||||||
$tableField = new ComplexTableField($this, $relationship, $component, $relationshipFields, "getCMSFields", '', '', $filterJoin);
|
$tableField = new ComplexTableField($this, $relationship, $component, $relationshipFields, "getCMSFields", $filterWhere, '', $filterJoin);
|
||||||
$tableField->popupClass = "ScaffoldingComplexTableField_Popup";
|
$tableField->popupClass = "ScaffoldingComplexTableField_Popup";
|
||||||
$fieldSet->addFieldToTab("Root.$relationship", $tableField);
|
$fieldSet->addFieldToTab("Root.$relationship", $tableField);
|
||||||
}
|
}
|
||||||
@ -1112,6 +1113,12 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getManyManyFilter($componentName, $baseTable) {
|
||||||
|
list($parentClass, $componentClass, $parentField, $componentField, $table) = $this->many_many($componentName);
|
||||||
|
|
||||||
|
return "`$table`.`$parentField` = '{$this->ID}'";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the class of a one-to-one component. If $component is null, return all of the one-to-one components and their classes.
|
* Return the class of a one-to-one component. If $component is null, return all of the one-to-one components and their classes.
|
||||||
*
|
*
|
||||||
|
@ -135,9 +135,14 @@ class Debug {
|
|||||||
if(!Director::isLive()) {
|
if(!Director::isLive()) {
|
||||||
$caller = Debug::caller();
|
$caller = Debug::caller();
|
||||||
$file = basename($caller['file']);
|
$file = basename($caller['file']);
|
||||||
echo "<p style=\"background-color: white; color: black; width: 95%; margin: 0.5em; padding: 0.3em; border: 1px #CCC solid\">\n";
|
if(Director::is_cli()) {
|
||||||
if($showHeader) echo "<b>Debug (line $caller[line] of $file):</b>\n ";
|
if($showHeader) echo "Debug (line $caller[line] of $file):\n ";
|
||||||
echo Convert::raw2xml(trim($message)) . "</p>\n";
|
echo trim($message) . "\n";
|
||||||
|
} else {
|
||||||
|
echo "<p style=\"background-color: white; color: black; width: 95%; margin: 0.5em; padding: 0.3em; border: 1px #CCC solid\">\n";
|
||||||
|
if($showHeader) echo "<b>Debug (line $caller[line] of $file):</b>\n ";
|
||||||
|
echo Convert::raw2xml(trim($message)) . "</p>\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,20 +213,7 @@ class Debug {
|
|||||||
echo "<p>Line <strong>$errline</strong> in <strong>$errfile</strong></p>";
|
echo "<p>Line <strong>$errline</strong> in <strong>$errfile</strong></p>";
|
||||||
echo '</div>';
|
echo '</div>';
|
||||||
echo '<div class="trace"><h3>Source</h3>';
|
echo '<div class="trace"><h3>Source</h3>';
|
||||||
$lines = file($errfile);
|
Debug::showLines($errfile, $errline);
|
||||||
$offset = $errline-10;
|
|
||||||
$lines = array_slice($lines, $offset, 16);
|
|
||||||
echo '<pre>';
|
|
||||||
$offset++;
|
|
||||||
foreach($lines as $line) {
|
|
||||||
$line = htmlentities($line);
|
|
||||||
if ($offset == $errline) {
|
|
||||||
echo "<span>$offset</span> <span class=\"error\">$line</span>";
|
|
||||||
} else {
|
|
||||||
echo "<span>$offset</span> $line";
|
|
||||||
}
|
|
||||||
$offset++;
|
|
||||||
}
|
|
||||||
echo '</pre><h3>Trace</h3>';
|
echo '</pre><h3>Trace</h3>';
|
||||||
Debug::backtrace();
|
Debug::backtrace();
|
||||||
echo '</div>';
|
echo '</div>';
|
||||||
@ -230,6 +222,24 @@ class Debug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function showLines($errfile, $errline) {
|
||||||
|
$lines = file($errfile);
|
||||||
|
$offset = $errline-10;
|
||||||
|
$lines = array_slice($lines, $offset, 16);
|
||||||
|
echo '<pre>';
|
||||||
|
$offset++;
|
||||||
|
foreach($lines as $line) {
|
||||||
|
$line = htmlentities($line);
|
||||||
|
if ($offset == $errline) {
|
||||||
|
echo "<span>$offset</span> <span class=\"error\">$line</span>";
|
||||||
|
} else {
|
||||||
|
echo "<span>$offset</span> $line";
|
||||||
|
}
|
||||||
|
$offset++;
|
||||||
|
}
|
||||||
|
echo '</pre>';
|
||||||
|
}
|
||||||
|
|
||||||
static function emailError($emailAddress, $errno, $errstr, $errfile, $errline, $errcontext, $errorType = "Error") {
|
static function emailError($emailAddress, $errno, $errstr, $errfile, $errline, $errcontext, $errorType = "Error") {
|
||||||
if(strtolower($errorType) == 'warning') {
|
if(strtolower($errorType) == 'warning') {
|
||||||
$colour = "orange";
|
$colour = "orange";
|
||||||
|
286
dev/SapphireTestReporter.php
Normal file
286
dev/SapphireTestReporter.php
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gathers details about PHPUnit2 test suites as they
|
||||||
|
* are been executed. This does not actually format any output
|
||||||
|
* but simply gathers extended information about the overall
|
||||||
|
* results of all suites & their tests for use elsewhere.
|
||||||
|
*
|
||||||
|
* Changelog:
|
||||||
|
* 0.6 First created [David Spurr]
|
||||||
|
* 0.7 Added fix to getTestException provided [Glen Ogilvie]
|
||||||
|
*
|
||||||
|
* @version 0.7 2006-03-12
|
||||||
|
* @author David Spurr
|
||||||
|
*/
|
||||||
|
require_once 'PHPUnit/Framework/TestResult.php';
|
||||||
|
require_once 'PHPUnit/Framework/TestListener.php';
|
||||||
|
|
||||||
|
/**#@+
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Failure test status constant
|
||||||
|
*/
|
||||||
|
define('TEST_FAILURE', -1);
|
||||||
|
/**
|
||||||
|
* Error test status constant
|
||||||
|
*/
|
||||||
|
define('TEST_ERROR', 0);
|
||||||
|
/**
|
||||||
|
* Success test status constant
|
||||||
|
*/
|
||||||
|
define('TEST_SUCCESS', 1);
|
||||||
|
/**
|
||||||
|
* Incomplete test status constant
|
||||||
|
*/
|
||||||
|
define('TEST_INCOMPLETE', 2);
|
||||||
|
/**#@-*/
|
||||||
|
|
||||||
|
class SapphireTestReporter implements PHPUnit_Framework_TestListener {
|
||||||
|
/**
|
||||||
|
* Holds array of suites and total number of tests run
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $suiteResults;
|
||||||
|
/**
|
||||||
|
* Holds data of current suite that is been run
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $currentSuite;
|
||||||
|
/**
|
||||||
|
* Holds data of current test that is been run
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $currentTest;
|
||||||
|
/**
|
||||||
|
* Whether PEAR Benchmark_Timer is available for timing
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
private $hasTimer;
|
||||||
|
/**
|
||||||
|
* Holds the PEAR Benchmark_Timer object
|
||||||
|
* @var obj Benchmark_Timer
|
||||||
|
*/
|
||||||
|
private $timer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, checks to see availability of PEAR Benchmark_Timer and
|
||||||
|
* sets up basic properties
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
@include_once 'Benchmark/Timer.php';
|
||||||
|
if(class_exists('Benchmark_Timer')) {
|
||||||
|
$this->timer = new Benchmark_Timer();
|
||||||
|
$this->hasTimer = true;
|
||||||
|
} else {
|
||||||
|
$this->hasTimer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->suiteResults = array(
|
||||||
|
'suites' => array(), // array of suites run
|
||||||
|
'hasTimer' => $this->hasTimer, // availability of PEAR Benchmark_Timer
|
||||||
|
'totalTests' => 0 // total number of tests run
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the suite results
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array Suite results
|
||||||
|
*/
|
||||||
|
public function getSuiteResults() {
|
||||||
|
return $this->suiteResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the container for result details of the current test suite when
|
||||||
|
* each suite is first run
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param obj PHPUnit2_Framework_TestSuite, the suite that is been run
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function startTestSuite( PHPUnit_Framework_TestSuite $suite) {
|
||||||
|
if(strlen($suite->getName())) {
|
||||||
|
$this->currentSuite = array(
|
||||||
|
'suite' => $suite, // the test suite
|
||||||
|
'tests' => array(), // the tests in the suite
|
||||||
|
'errors' => 0, // number of tests with errors
|
||||||
|
'failures' => 0, // number of tests which failed
|
||||||
|
'incomplete' => 0); // number of tests that were not completed correctly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the container for result details of the current test when each
|
||||||
|
* test is first run
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param obj PHPUnit_Framework_Test, the test that is being run
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function startTest(PHPUnit_Framework_Test $test) {
|
||||||
|
if($test instanceof PHPUnit_Framework_TestCase) {
|
||||||
|
$this->currentTest = array(
|
||||||
|
'name' => preg_replace('(\(.*\))', '', $test->toString()), // the name of the test (without the suite name)
|
||||||
|
'timeElapsed' => 0, // execution time of the test
|
||||||
|
'status' => TEST_SUCCESS, // status of the test execution
|
||||||
|
'message' => '', // user message of test result
|
||||||
|
'exception' => NULL, // original caught exception thrown by test upon failure/error
|
||||||
|
'uid' => md5(microtime()) // a unique ID for this test (used for identification purposes in results)
|
||||||
|
);
|
||||||
|
if($this->hasTimer) $this->timer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the failure detail to the current test and increases the failure
|
||||||
|
* count for the current suite
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param obj PHPUnit_Framework_Test, current test that is being run
|
||||||
|
* @param obj PHPUnit_Framework_AssertationFailedError, PHPUnit error
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) {
|
||||||
|
$this->currentSuite['failures']++;
|
||||||
|
$this->currentTest['status'] = TEST_FAILURE;
|
||||||
|
$this->currentTest['message'] = $e->toString();
|
||||||
|
$this->currentTest['exception'] = $this->getTestException($test, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the error detail to the current test and increases the error
|
||||||
|
* count for the current suite
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param obj PHPUnit_Framework_Test, current test that is being run
|
||||||
|
* @param obj PHPUnit_Framework_AssertationFailedError, PHPUnit error
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) {
|
||||||
|
$this->currentSuite['errors']++;
|
||||||
|
$this->currentTest['status'] = TEST_ERROR;
|
||||||
|
$this->currentTest['message'] = $e->getMessage();
|
||||||
|
$this->currentTest['exception'] = $this->getTestException($test, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the test incomplete detail to the current test and increases the incomplete
|
||||||
|
* count for the current suite
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param obj PHPUnit_Framework_Test, current test that is being run
|
||||||
|
* @param obj PHPUnit_Framework_AssertationFailedError, PHPUnit error
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) {
|
||||||
|
$this->currentSuite['incomplete']++;
|
||||||
|
$this->currentTest['status'] = TEST_INCOMPLETE;
|
||||||
|
$this->currentTest['message'] = $e->toString();
|
||||||
|
$this->currentTest['exception'] = $this->getTestException($test, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not used
|
||||||
|
*
|
||||||
|
* @param PHPUnit_Framework_Test $test
|
||||||
|
* @param unknown_type $time
|
||||||
|
*/
|
||||||
|
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) {
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upon completion of a test, records the execution time (if available) and adds the test to
|
||||||
|
* the tests performed in the current suite.
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param obj PHPUnit_Framework_Test, current test that is being run
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function endTest( PHPUnit_Framework_Test $test, $time) {
|
||||||
|
if($this->hasTimer) {
|
||||||
|
$this->timer->stop();
|
||||||
|
$this->currentTest['timeElapsed'] = $this->timer->timeElapsed();
|
||||||
|
}
|
||||||
|
array_push($this->currentSuite['tests'], $this->currentTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upon completion of a test suite adds the suite to the suties performed
|
||||||
|
*
|
||||||
|
* @acces public
|
||||||
|
* @param obj PHPUnit_Framework_TestSuite, current suite that is being run
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function endTestSuite( PHPUnit_Framework_TestSuite $suite) {
|
||||||
|
if(strlen($suite->getName())) {
|
||||||
|
array_push($this->suiteResults['suites'], $this->currentSuite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trys to get the original exception thrown by the test on failure/error
|
||||||
|
* to enable us to give a bit more detail about the failure/error
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param obj PHPUnit_Framework_Test, current test that is being run
|
||||||
|
* @param obj PHPUnit_Framework_AssertationFailedError, PHPUnit error
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getTestException(PHPUnit_Framework_Test $test, Exception $e) {
|
||||||
|
// get the name of the testFile from the test
|
||||||
|
$testName = ereg_replace('(.*)\((.*[^)])\)', '\\2', $test->toString());
|
||||||
|
$trace = $e->getTrace();
|
||||||
|
// loop through the exception trace to find the original exception
|
||||||
|
for($i = 0; $i < count($trace); $i++) {
|
||||||
|
|
||||||
|
if(array_key_exists('file', $trace[$i])) {
|
||||||
|
if(stristr($trace[$i]['file'], $testName.'.php') != false) return $trace[$i];
|
||||||
|
}
|
||||||
|
if(array_key_exists('file:protected', $trace[$i])) {
|
||||||
|
if(stristr($trace[$i]['file:protected'], $testName.'.php') != false) return $trace[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display error bar if it exists
|
||||||
|
*/
|
||||||
|
public function writeResults() {
|
||||||
|
$passCount = 0;
|
||||||
|
$failCount = 0;
|
||||||
|
$testCount = 0;
|
||||||
|
$errorCount = 0;
|
||||||
|
|
||||||
|
foreach($this->suiteResults['suites'] as $suite) {
|
||||||
|
foreach($suite['tests'] as $test) {
|
||||||
|
$testCount++;
|
||||||
|
($test['status'] == 1) ? $passCount++ : $failCount++;
|
||||||
|
if ($test['status'] == -1) {
|
||||||
|
echo "<div class=\"failure\"><span>⊗ ". $this->testNameToPhrase($test['name']) ."</span><br>";
|
||||||
|
echo "<pre>".htmlentities($test['message'])."</pre><br>";
|
||||||
|
echo "<code>In line {$test['exception']['line']} of {$test['exception']['file']}</code></div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result = ($failCount > 0) ? 'fail' : 'pass';
|
||||||
|
echo "<div class=\"$result\">";
|
||||||
|
echo "<h2><span>$testCount</span> tests run: <span>$passCount</span> passes, <span>$failCount</span> fails, and <span>0</span> exceptions</h2>";
|
||||||
|
echo "</div>";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function testNameToPhrase($name) {
|
||||||
|
return ucfirst(preg_replace("/([a-z])([A-Z])/", "$1 $2", $name));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -31,8 +31,8 @@ class TestRunner extends Controller {
|
|||||||
private static $default_reporter;
|
private static $default_reporter;
|
||||||
|
|
||||||
static $url_handlers = array(
|
static $url_handlers = array(
|
||||||
'' => 'index',
|
'' => 'browse',
|
||||||
'$TestCase' => 'only'
|
'$TestCase' => 'only',
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +53,7 @@ class TestRunner extends Controller {
|
|||||||
/**
|
/**
|
||||||
* Run all test classes
|
* Run all test classes
|
||||||
*/
|
*/
|
||||||
function index() {
|
function all() {
|
||||||
if(hasPhpUnit()) {
|
if(hasPhpUnit()) {
|
||||||
$tests = ClassInfo::subclassesFor('SapphireTest');
|
$tests = ClassInfo::subclassesFor('SapphireTest');
|
||||||
array_shift($tests);
|
array_shift($tests);
|
||||||
@ -65,6 +65,16 @@ class TestRunner extends Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Browse all enabled test cases in the environment
|
||||||
|
*/
|
||||||
|
function browse() {
|
||||||
|
$tests = ClassInfo::subclassesFor('SapphireTest');
|
||||||
|
foreach ($tests as $test) {
|
||||||
|
echo "<h3><a href=\"$test\">$test</a></h3>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function coverage() {
|
function coverage() {
|
||||||
if(hasPhpUnit()) {
|
if(hasPhpUnit()) {
|
||||||
ManifestBuilder::includeEverything();
|
ManifestBuilder::includeEverything();
|
||||||
@ -86,7 +96,7 @@ class TestRunner extends Controller {
|
|||||||
if(class_exists($className)) {
|
if(class_exists($className)) {
|
||||||
$this->runTests(array($className));
|
$this->runTests(array($className));
|
||||||
} else {
|
} else {
|
||||||
echo "Class '$className' not found";
|
if ($className == 'all') $this->all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,11 +104,15 @@ class TestRunner extends Controller {
|
|||||||
if(!Director::is_cli()) {
|
if(!Director::is_cli()) {
|
||||||
self::$default_reporter->writeHeader();
|
self::$default_reporter->writeHeader();
|
||||||
echo '<div class="info">';
|
echo '<div class="info">';
|
||||||
echo "<h1>Sapphire PHPUnit Test Runner</h1>";
|
if (count($classList) > 1) {
|
||||||
echo "<p>Using the following subclasses of SapphireTest for testing: " . implode(", ", $classList) . "</p>";
|
echo "<h1>Sapphire Tests</h1>";
|
||||||
|
echo "<p>Running test cases: " . implode(", ", $classList) . "</p>";
|
||||||
|
} else {
|
||||||
|
echo "<h1>{$classList[0]}</h1>";
|
||||||
|
echo "<p>Running test case:</p>";
|
||||||
|
}
|
||||||
echo "</div>";
|
echo "</div>";
|
||||||
echo '<div class="trace">';
|
echo '<div class="trace">';
|
||||||
echo "<pre>";
|
|
||||||
} else {
|
} else {
|
||||||
echo "Sapphire PHPUnit Test Runner\n";
|
echo "Sapphire PHPUnit Test Runner\n";
|
||||||
echo "Using the following subclasses of SapphireTest for testing: " . implode(", ", $classList) . "\n\n";
|
echo "Using the following subclasses of SapphireTest for testing: " . implode(", ", $classList) . "\n\n";
|
||||||
@ -114,18 +128,23 @@ class TestRunner extends Controller {
|
|||||||
$suite->addTest(new PHPUnit_Framework_TestSuite($className));
|
$suite->addTest(new PHPUnit_Framework_TestSuite($className));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$reporter = new SapphireTestReporter();
|
||||||
|
$results = new PHPUnit_Framework_TestResult();
|
||||||
|
$results->addListener($reporter);
|
||||||
|
|
||||||
/*, array("reportDirectory" => "/Users/sminnee/phpunit-report")*/
|
/*, array("reportDirectory" => "/Users/sminnee/phpunit-report")*/
|
||||||
if($coverage) {
|
if($coverage) {
|
||||||
$testResult = PHPUnit_TextUI_TestRunner::run($suite, array("reportDirectory" => "../assets/coverage-report"));
|
$suite->run($results);
|
||||||
} else {
|
//$testResult = PHPUnit_TextUI_TestRunner::run($suite, array("reportDirectory" => "../assets/coverage-report"));
|
||||||
$testResult = PHPUnit_TextUI_TestRunner::run($suite);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($coverage) {
|
|
||||||
$coverageURL = Director::absoluteURL('assets/coverage-report');
|
$coverageURL = Director::absoluteURL('assets/coverage-report');
|
||||||
echo "<p><a href=\"$coverageURL\">Coverage report available here</a></p>";
|
echo "<p><a href=\"$coverageURL\">Coverage report available here</a></p>";
|
||||||
|
} else {
|
||||||
|
$suite->run($results);
|
||||||
|
//$testResult = PHPUnit_TextUI_TestRunner::run($suite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$reporter->writeResults();
|
||||||
|
|
||||||
if(!Director::is_cli()) echo '</div>';
|
if(!Director::is_cli()) echo '</div>';
|
||||||
|
|
||||||
// Put the error handlers back
|
// Put the error handlers back
|
||||||
|
@ -895,6 +895,10 @@ class ScaffoldingComplexTableField_Popup extends Form {
|
|||||||
protected $sourceClass;
|
protected $sourceClass;
|
||||||
protected $dataObject;
|
protected $dataObject;
|
||||||
|
|
||||||
|
public static $allowed_actions = array(
|
||||||
|
'filter', 'record', 'httpSubmission', 'handleAction'
|
||||||
|
);
|
||||||
|
|
||||||
function __construct($controller, $name, $fields, $validator, $readonly, $dataObject) {
|
function __construct($controller, $name, $fields, $validator, $readonly, $dataObject) {
|
||||||
$this->dataObject = $dataObject;
|
$this->dataObject = $dataObject;
|
||||||
|
|
||||||
@ -945,6 +949,8 @@ class ScaffoldingComplexTableField_Popup extends Form {
|
|||||||
$saveAction->addExtraClass('save');
|
$saveAction->addExtraClass('save');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$fields->push(new HiddenField("ComplexTableField_Path", Director::absoluteBaseURL()));
|
||||||
|
|
||||||
parent::__construct($controller, $name, $fields, $actions, $validator);
|
parent::__construct($controller, $name, $fields, $actions, $validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -952,6 +958,68 @@ class ScaffoldingComplexTableField_Popup extends Form {
|
|||||||
return $this->renderWith('ComplexTableField_Form');
|
return $this->renderWith('ComplexTableField_Form');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a generic action passed in by the URL mapping.
|
||||||
|
*
|
||||||
|
* @param HTTPRequest $request
|
||||||
|
*/
|
||||||
|
public function handleAction($request) {
|
||||||
|
$action = str_replace("-","_",$request->param('Action'));
|
||||||
|
if(!$this->action) $this->action = 'index';
|
||||||
|
|
||||||
|
if($this->checkAccessAction($action)) {
|
||||||
|
if($this->hasMethod($action)) {
|
||||||
|
$result = $this->$action($request);
|
||||||
|
|
||||||
|
// Method returns an array, that is used to customise the object before rendering with a template
|
||||||
|
if(is_array($result)) {
|
||||||
|
return $this->getViewer($action)->process($this->customise($result));
|
||||||
|
|
||||||
|
// Method returns a string / object, in which case we just return that
|
||||||
|
} else {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is no method, in which case we just render this object using a (possibly alternate) template
|
||||||
|
} else {
|
||||||
|
return $this->getViewer($action)->process($this);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $this->httpError(403, "Action '$action' isn't allowed on class $this->class");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action to render results for an autocomplete filter.
|
||||||
|
*
|
||||||
|
* @param HTTPRequest $request
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function filter($request) {
|
||||||
|
//$model = singleton($this->modelClass);
|
||||||
|
$context = $this->dataObject->getDefaultSearchContext();
|
||||||
|
$value = $request->getVar('q');
|
||||||
|
$results = $context->getResults(array("Name"=>$value));
|
||||||
|
header("Content-Type: text/plain");
|
||||||
|
foreach($results as $result) {
|
||||||
|
echo $result->Name . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action to populate edit box with a single data object via Ajax query
|
||||||
|
*/
|
||||||
|
function record($request) {
|
||||||
|
$type = $request->getVar('type');
|
||||||
|
$value = $request->getVar('value');
|
||||||
|
if ($type && $value) {
|
||||||
|
$record = DataObject::get_one($this->dataObject->class, "$type = '$value'");
|
||||||
|
header("Content-Type: text/plain");
|
||||||
|
echo json_encode(array("record"=>$record->toMap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
@ -118,6 +118,7 @@ class Form extends RequestHandlingData {
|
|||||||
|
|
||||||
static $url_handlers = array(
|
static $url_handlers = array(
|
||||||
'field/$FieldName!' => 'handleField',
|
'field/$FieldName!' => 'handleField',
|
||||||
|
'$Action!' => 'handleAction',
|
||||||
'POST ' => 'httpSubmission',
|
'POST ' => 'httpSubmission',
|
||||||
'GET ' => 'httpSubmission',
|
'GET ' => 'httpSubmission',
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,24 @@
|
|||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
|
|
||||||
|
resourcePath = jQuery('form').attr('action');
|
||||||
|
|
||||||
jQuery("fieldset input:first").attr('autocomplete', 'off').autocomplete({list: ["mark rickerby", "maxwell sparks"]});
|
jQuery("fieldset input:first").attr('autocomplete', 'off').autocomplete({list: ["mark rickerby", "maxwell sparks"]});
|
||||||
|
|
||||||
|
jQuery("fieldset input:first").bind('activate.autocomplete', function(e){
|
||||||
|
|
||||||
|
type = jQuery("fieldset input:first").attr('name');
|
||||||
|
value = jQuery("fieldset input:first").val();
|
||||||
|
|
||||||
|
jQuery.getJSON(resourcePath + '/record', {'type':type, 'value':value}, function(data) {
|
||||||
|
jQuery('form input').each(function(i, elm){
|
||||||
|
if(elm.name in data.record) {
|
||||||
|
val = data.record[elm.name];
|
||||||
|
if (val != null) elm.setAttribute('value', val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
2
sake
2
sake
@ -15,7 +15,7 @@ if [ "$1" = "installsake" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Find the PHP binary
|
# Find the PHP binary
|
||||||
for candidatephp in php5 php; do
|
for candidatephp in "php5 php"; do
|
||||||
if [ -f `which $candidatephp` ]; then
|
if [ -f `which $candidatephp` ]; then
|
||||||
php=`which $candidatephp`
|
php=`which $candidatephp`
|
||||||
break
|
break
|
||||||
|
@ -125,11 +125,10 @@ class SearchContext extends Object {
|
|||||||
|
|
||||||
if($existingQuery) {
|
if($existingQuery) {
|
||||||
$query = $existingQuery;
|
$query = $existingQuery;
|
||||||
$query->select = array_merge($query->select,$fields);
|
|
||||||
} else {
|
} else {
|
||||||
$query = $model->buildSQL();
|
$query = $model->buildSQL();
|
||||||
$query->select($fields);
|
|
||||||
}
|
}
|
||||||
|
$query->select = array_merge($query->select,$fields);
|
||||||
|
|
||||||
$SQL_limit = Convert::raw2sql($limit);
|
$SQL_limit = Convert::raw2sql($limit);
|
||||||
$query->limit($SQL_limit);
|
$query->limit($SQL_limit);
|
||||||
|
29
search/filters/CollectionFilter.php
Normal file
29
search/filters/CollectionFilter.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Checks if a value is in a given set.
|
||||||
|
* SQL syntax used: Column IN ('val1','val2')
|
||||||
|
*
|
||||||
|
* @todo Add negation (NOT IN)6
|
||||||
|
*
|
||||||
|
* @author Silverstripe Ltd., Ingo Schommer (<firstname>@silverstripe.com)
|
||||||
|
*/
|
||||||
|
class CollectionFilter extends SearchFilter {
|
||||||
|
|
||||||
|
public function apply(SQLQuery $query) {
|
||||||
|
$query = $this->applyRelation($query);
|
||||||
|
$values = explode(',',$this->value);
|
||||||
|
if(!$values) return false;
|
||||||
|
|
||||||
|
for($i=0; $i<count($values); $i++) {
|
||||||
|
if(!is_numeric($values[$i])) {
|
||||||
|
// @todo Fix string replacement to only replace leading and tailing quotes
|
||||||
|
$values[$i] = str_replace("'", '', $values[$i]);
|
||||||
|
$values[$i] = Convert::raw2sql($values[$i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$SQL_valueStr = "'" . implode("','", $values) . "'";
|
||||||
|
return $query->where("{$this->getName()} IN ({$SQL_valueStr})");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
@ -99,7 +99,8 @@ class SearchContextTest extends SapphireTest {
|
|||||||
$params = array(
|
$params = array(
|
||||||
"ExactMatch" => "Match Me Exactly",
|
"ExactMatch" => "Match Me Exactly",
|
||||||
"PartialMatch" => "partially",
|
"PartialMatch" => "partially",
|
||||||
"Negation" => "undisclosed"
|
"Negation" => "undisclosed",
|
||||||
|
"CollectionMatch" => "ExistingCollectionValue,NonExistingCollectionValue,4,Inline'Quotes'",
|
||||||
);
|
);
|
||||||
|
|
||||||
$results = $context->getResults($params);
|
$results = $context->getResults($params);
|
||||||
@ -209,13 +210,15 @@ class SearchContextTest_AllFilterTypes extends DataObject implements TestOnly {
|
|||||||
"Negation" => "Text",
|
"Negation" => "Text",
|
||||||
"SubstringMatch" => "Text",
|
"SubstringMatch" => "Text",
|
||||||
"HiddenValue" => "Text",
|
"HiddenValue" => "Text",
|
||||||
|
"CollectionMatch" => "Text",
|
||||||
);
|
);
|
||||||
|
|
||||||
static $searchable_fields = array(
|
static $searchable_fields = array(
|
||||||
"ExactMatch" => "ExactMatchFilter",
|
"ExactMatch" => "ExactMatchFilter",
|
||||||
"PartialMatch" => "PartialMatchFilter",
|
"PartialMatch" => "PartialMatchFilter",
|
||||||
"Negation" => "NegationFilter",
|
"Negation" => "NegationFilter",
|
||||||
"SubstringMatch" => "SubstringFilter"
|
"SubstringMatch" => "SubstringFilter",
|
||||||
|
"CollectionMatch" => "CollectionFilter",
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -62,3 +62,4 @@ SearchContextTest_AllFilterTypes:
|
|||||||
PartialMatch: Match me partially
|
PartialMatch: Match me partially
|
||||||
Negation: Shouldnt match me
|
Negation: Shouldnt match me
|
||||||
HiddenValue: Filtered value
|
HiddenValue: Filtered value
|
||||||
|
CollectionMatch: ExistingCollectionValue
|
Loading…
Reference in New Issue
Block a user