mirror of
				https://gitlab.com/hashborgir/d2tools.git
				synced 2025-11-03 17:27:46 -06:00 
			
		
		
		
	
		
			
				
	
	
		
			449 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			449 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?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';
 | 
						|
	}
 | 
						|
}
 | 
						|
 |