<?php
namespace RedUNIT\Base;
use RedUNIT\Base as Base;
use RedBeanPHP\Facade as R;
use RedBeanPHP\RedException as RedException;
use RedBeanPHP\QueryWriter as QueryWriter;
use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
use RedBeanPHP\Logger\RDefault as Logger;
/**
* Update
*
* Tests basic update functionality - however this test suite
* has grown to cover various other scenarios involving updates as
* well, including setting of property filters (necessary for
* spatial tools in MySQL), storiging INF value and more...
*
* @file RedUNIT/Base/Update.php
* @desc Tests basic storage features through OODB class.
* @author Gabor de Mooij and the RedBeanPHP Community
* @license New BSD/GPLv2
*
* (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
* This source file is subject to the New BSD/GPLv2 License that is bundled
* with this source code in the file license.txt.
*/
class Update extends Base
{
/**
* Tests whether no unncessary DESCRIBE-queries are executed,
* (Commit 3b8ce88e5b796bfde6485ab0a51a4fcfb1bcf0fa by davidsickmiller).
* Even thtough we add 2 properties, only 1 DESCRIBE query is necessary
* to load the column cache.
*/
public function testModifySchemaColCache()
{
R::nuke();
$toolbox = R::getToolbox();
$repository = $toolbox->getRedBean()->getCurrentRepository();
$database = $toolbox->getDatabaseAdapter()->getDatabase();
$logger = new Logger;
$database->setLogger( $logger );
$bean = R::dispense('bean');
$bean->property1 = 'test';
$bean->property2 = 'test'; //should not cause 2nd DESCRIBE.
R::startLogging();
R::store( $bean );
$logger = R::getLogger();
asrt(
count( $logger->grep('DESCRIBE') ) +
count( $logger->grep('SELECT column_name') ) +
count( $logger->grep('SHOW COLUMNS') ) + //CUBRID
count( $logger->grep('PRAGMA table_info') )
, 1);
R::stopLogging();
//new round, same results, no cache between beans
R::nuke();
$bean = R::dispense('bean');
$bean->property1 = 'test';
$bean->property2 = 'test'; //should not cause 2nd DESCRIBE.
R::startLogging();
R::store( $bean );
$logger = R::getLogger();
asrt(
count( $logger->grep('DESCRIBE') ) +
count( $logger->grep('SELECT column_name') ) +
count( $logger->grep('SHOW COLUMNS') ) + //CUBRID
count( $logger->grep('PRAGMA table_info') )
, 1);
R::stopLogging();
}
/**
* Test whether we can use SQL filters and
* whether they are being applied properly for
* different types of SELECT queries in the QueryWriter.
*/
public function testSQLFilters()
{
R::nuke();
AQueryWriter::setSQLFilters(array(
QueryWriter::C_SQLFILTER_READ => array(
'book' => array( 'title' => ' LOWER(book.title) '),
),
QueryWriter::C_SQLFILTER_WRITE => array(
'book' => array( 'title' => ' UPPER(?) '),
),
));
$book = R::dispense( 'book' );
$book->title = 'story';
R::store( $book );
asrt( R::getCell( 'SELECT title FROM book WHERE id = ?', array( $book->id ) ), 'STORY' );
$book = $book->fresh();
asrt( $book->title, 'story' );
$library = R::dispense( 'library' );
$library->sharedBookList[] = $book;
R::store( $library );
$library = $library->fresh();
$books = $library->sharedBookList;
$book = reset( $books );
asrt( $book->title, 'story' );
$otherBook = R::dispense('book');
$otherBook->sharedBook[] = $book;
R::store( $otherBook );
$otherBook = $otherBook->fresh();
$books = $otherBook->sharedBookList;
$book = reset( $books );
asrt( $book->title, 'story' );
$links = $book->ownBookBookList;
$link = reset( $links );
$link->shelf = 'x13';
AQueryWriter::setSQLFilters(array(
QueryWriter::C_SQLFILTER_READ => array(
'book' => array( 'title' => ' LOWER(book.title) '),
'book_book' => array( 'shelf' => ' LOWER(book_book.shelf) '),
),
QueryWriter::C_SQLFILTER_WRITE => array(
'book' => array( 'title' => ' UPPER(?) '),
'book_book' => array( 'shelf' => ' UPPER(?) ')
),
));
R::store( $link );
asrt( R::getCell( 'SELECT shelf FROM book_book WHERE id = ?', array( $link->id ) ), 'X13' );
$otherBook = $otherBook->fresh();
unset($book->sharedBookList[$otherBook->id]);
R::store( $book );
AQueryWriter::setSQLFilters(array());
}
/**
* Test unsetting properties.
*
* @return void
*/
public function testUnsetUpdate()
{
R::nuke();
$book = R::dispense( 'book' );
$book->name = 'x';
$book->price = 40;
R::store( $book );
$book = $book->fresh();
$book->name = 'y';
unset( $book->name );
R::store( $book );
$book = $book->fresh();
asrt( $book->name, 'x' );
asrt( (int) $book->price, 40 );
$book->price = 30;
R::store( $book );
$book = $book->fresh();
asrt( $book->name, 'x' );
asrt( (int) $book->price, 30 );
$book->price = 20;
unset( $book->price );
$book->name = 'y';
R::store( $book );
$book = $book->fresh();
asrt( $book->name, 'y' );
asrt( (int) $book->price, 30 );
}
/**
* Tests whether we can update or unset a parent bean
* with an alias without having to use fetchAs and
* without loading the aliased bean causing table-not-found
* errors.
*/
public function testUpdatingParentBeansWithAliases()
{
testpack( 'Test updating parent beans with aliases' );
R::nuke();
$trans = R::dispense( 'transaction' );
$seller = R::dispense( 'user' );
$trans->seller = $seller;
$id = R::store( $trans );
R::freeze( TRUE );
$trans = R::load( 'transaction', $id );
//should not try to load seller, should not require fetchAs().
try {
$trans->seller = R::dispense( 'user' );
pass();
} catch( Exception $e ) {
fail();
}
$trans = R::load( 'transaction', $id );
//same for unset...
try {
unset( $trans->seller );
pass();
} catch ( Exception $e ) {
fail();
}
R::freeze( FALSE );
$account = R::dispense( 'user' );
asrt( count( $account->alias( 'seller' )->ownTransaction ), 0 );
$account->alias( 'seller' )->ownTransaction = R::dispense( 'transaction', 10 );
$account->alias( 'boo' ); //try to trick me...
$id = R::store( $account );
R::freeze( TRUE );
$account = R::load( 'user', $id );
asrt( count( $account->alias( 'seller' )->ownTransaction ), 10 );
//you cannot unset a list
unset( $account->alias( 'seller' )->ownTransaction );
$id = R::store( $account );
$account = R::load( 'user', $id );
asrt( count( $account->alias( 'seller' )->ownTransaction ), 10 );
$account->alias( 'seller' )->ownTransaction = array();
$id = R::store( $account );
$account = R::load( 'user', $id );
asrt(count($account->alias( 'seller' )->ownTransaction), 0 );
asrt(count($account->ownTransaction), 0 );
R::freeze( FALSE );
//but also make sure we don't cause extra column issue #335
R::nuke();
$building = R::dispense('building');
$village = R::dispense('village');
$building->village = $village;
R::store($building);
$building = $building->fresh();
$building->village = NULL;
R::store($building);
$building = $building->fresh();
$columns = R::inspect('building');
asrt( isset( $columns['village'] ), FALSE );
asrt( isset( $building->village ), FALSE );
R::nuke();
$building = R::dispense('building');
$village = R::dispense('village');
$building->village = $village;
R::store($building);
$building = $building->fresh();
unset($building->village);
R::store($building);
$building = $building->fresh();
$columns = R::inspect('building');
asrt( isset( $columns['village'] ), FALSE );
asrt( isset( $building->village ), FALSE );
$building = R::dispense('building');
$village = R::dispense('village');
$building->village = $village;
R::store($building);
$building = $building->fresh();
$building->village = FALSE;
R::store($building);
$building = $building->fresh();
$columns = R::inspect('building');
asrt( isset( $columns['village'] ), FALSE );
asrt( isset( $building->village ), FALSE );
}
/**
* All kinds of tests for basic CRUD.
*
* Does the data survive?
*
* @return void
*/
public function testUpdatingBeans()
{
testpack( 'Test basic support UUID/override ID default value' );
$bean = R::dispense( 'bean' );
R::store( $bean );
if ($this->currentlyActiveDriverID === 'mysql') {
//otherwise UTF8 causes index overflow in mysql: SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
R::exec('alter table bean modify column id char(3);');
} else {
R::getWriter()->widenColumn( 'bean', 'id', R::getWriter()->scanType( 'abc' ) );
}
$bean->id = 'abc';
R::store( $bean );
asrt( $bean->id, 'abc' );
testpack( 'Test Update' );
try {
R::store( array() );
fail();
} catch ( RedException $e ) {
pass();
}
$toolbox = R::getToolBox();
$adapter = $toolbox->getDatabaseAdapter();
$writer = $toolbox->getWriter();
$redbean = $toolbox->getRedBean();
$pdo = $adapter->getDatabase();
$page = $redbean->dispense( "page" );
$page->name = "old name";
$id = $redbean->store( $page );
asrt( $page->getMeta( 'tainted' ), FALSE );
$page->setAttr( 'name', "new name" );
asrt( $page->getMeta( 'tainted' ), TRUE );
$id = $redbean->store( $page );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
// Null should == NULL after saving
$page->rating = NULL;
$newid = $redbean->store( $page );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( ( $page->rating === NULL ), TRUE );
asrt( !$page->rating, TRUE );
$page->rating = FALSE;
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( (bool) $page->rating, FALSE );
asrt( ( $page->rating == FALSE ), TRUE );
asrt( !$page->rating, TRUE );
$page->rating = TRUE;
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( (bool) $page->rating, TRUE );
asrt( ( $page->rating == TRUE ), TRUE );
asrt( ( $page->rating == TRUE ), TRUE );
$page->rating = NULL;
R::store( $page );
$page = R::load( 'page', $page->id );
asrt( $page->rating, NULL );
$page->rating = '1';
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( $page->rating, "1" );
$page->rating = "0";
$newid = $redbean->store( $page );
asrt( $page->rating, "0" );
$page->rating = 0;
$newid = $redbean->store( $page );
asrt( $page->rating, 0 );
$page->rating = "0";
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( !$page->rating, TRUE );
asrt( ( $page->rating == 0 ), TRUE );
asrt( ( $page->rating == FALSE ), TRUE );
$page->rating = 5;
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( strval( $page->rating ), "5" );
$page->rating = 300;
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( strval( $page->rating ), "300" );
$page->rating = -2;
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( strval( $page->rating ), "-2" );
$page->rating = 2.5;
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( ( $page->rating == 2.5 ), TRUE );
$page->rating = -3.3;
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( ( $page->rating == -3.3 ), TRUE );
$page->rating = "good";
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( $page->rating, "good" );
$longtext = str_repeat( 'great! because..', 100 );
$page->rating = $longtext;
$newid = $redbean->store( $page );
asrt( $newid, $id );
$page = $redbean->load( "page", $id );
asrt( $page->name, "new name" );
asrt( $page->rating, $longtext );
// Test leading zeros
$numAsString = "0001";
$page->numasstring = $numAsString;
$redbean->store( $page );
$page = $redbean->load( "page", $id );
asrt( $page->numasstring, "0001" );
$page->numnotstring = "0.123";
$redbean->store( $page );
$page = $redbean->load( "page", $id );
asrt( $page->numnotstring == 0.123, TRUE );
$page->numasstring2 = "00.123";
$redbean->store( $page );
$page = $redbean->load( "page", $id );
asrt( $page->numasstring2, "00.123" );
try {
$redbean->trash( array() );
fail();
} catch ( RedException $e ) {
pass();
}
$redbean->trash( $page );
asrt( (int) $pdo->GetCell( "SELECT count(*) FROM page" ), 0 );
}
/**
* Tests whether empty strings are preserved as such.
*
* @return void
*/
public function testEmptyStringShouldNotBeStoredAsInteger()
{
R::nuke();
$bean = R::dispense('bean');
$bean->str = '';
R::store($bean);
$bean = $bean->fresh();
asrt( ( $bean->str === '' ), TRUE);
}
/**
* Test handling of infinity values.
*
* @return void
*/
public function testStoringInf()
{
R::nuke();
$bean = R::dispense( 'bean' );
$bean->inf = INF;
R::store( $bean );
$bean = $bean->fresh();
asrt( ( $bean->inf === 'INF' ), TRUE );
asrt( ( $bean->inf == 'INF' ), TRUE );
$bean->modifyme = 'yes';
R::store( $bean );
$bean = $bean->fresh();
asrt( ( $bean->inf === 'INF' ), TRUE );
asrt( ( $bean->inf == 'INF' ), TRUE );
$bean->modifyme = 'yes';
}
}
|