I'm using DoctrineFixturesBundle to create test records before each test is executed. But it created a mess in my database, so I want to remove those added records after each test is finished. How can I do this without removing the whole database?
/**
* Function initializing test environment
*/
protected function setUp()
{
//
// set the client object for easier access (and cleaner code)
//
$this->client = static::createClient();
//
// create database fixtures
//
$container = $this->client->getContainer();
$doctrine = $container->get('doctrine');
$entityManager = $doctrine->getManager();
$userFixture = new LoadUsersData();
$userFixture->load($entityManager);
}
/**
* Function that runs when the testing is finished
*/
public function tearDown()
{
parent::tearDown();
//
// purge database fixtures
//
//
// close database connection
//
$this->em->close();
}
Related
Installing and using SoftDeleteable behavior extension for Doctrine 2 is quite easy. The problem usually is trying to disable it for some code part and enabling again. You may want to do this to:
load entity that is soft-deleted
remove entity from database entirely bypassing soft-delete filter
So how to disable it?
1. How to load soft-deleted entity
As per the documentation, disable filter for entity manager:
$em->getFilters()->disable('softdeleteable');
$object = $em->find('AppBundle:Object', 1); // soft-deleted entity will be loaded
To enable soft-delete again:
$em->getFilters()->enable('softdeleteable');
Note: $em->clear(); may be required before this line, if entity was already loaded with disabled soft-delete filter.
2. How to remove entity from database entirely
Even though it is not mentioned in documentation, the first solution does not work if you need to remove entity and bypass soft-delete filter. Filter needs to be removed from entity manager's event listeners:
// initiate an array for the removed listeners
$originalEventListeners = [];
// cycle through all registered event listeners
foreach ($em->getEventManager()->getListeners() as $eventName => $listeners) {
foreach ($listeners as $listener) {
if ($listener instanceof \Gedmo\SoftDeleteable\SoftDeleteableListener) {
// store the event listener, that gets removed
$originalEventListeners[$eventName] = $listener;
// remove the SoftDeletableSubscriber event listener
$em->getEventManager()->removeEventListener($eventName, $listener);
}
}
}
// remove the entity
$em->remove($object);
$em->flush($object); // or $em->flush();
// re-add the removed listener back to the event-manager
foreach ($originalEventListeners as $eventName => $listener) {
$em->getEventManager()->addEventListener($eventName, $listener);
}
References:
https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/softdeleteable.md
Force delete doctrine entity when using SoftDeletable by KnpLabs
Disable Soft Deleteable filter for hard delete record doesn't work
You can use a service to disable and reenable the soft delete filter behaviour:
<?php
namespace App\Util;
use Doctrine\ORM\EntityManagerInterface;
use Gedmo\SoftDeleteable\SoftDeleteableListener;
class SoftDeleteFilter
{
/**
* #var string
*/
const EVENT_NAME = 'onFlush';
/**
* #var object
*/
private $originalEventListener;
/**
* #param EntityManagerInterface $em
*/
public function removeSoftDeleteFilter(EntityManagerInterface $em)
{
foreach ($em->getEventManager()->getListeners() as $eventName => $listeners) {
foreach ($listeners as $listener) {
if ($listener instanceof SoftDeleteableListener) {
if ($eventName === self::EVENT_NAME) {
$this->originalEventListener = $listener;
$em->getEventManager()->removeEventListener($eventName, $listener);
}
}
}
}
}
/**
* #param EntityManagerInterface $em
*/
public function undoRemoveSoftDeleteFilter(EntityManagerInterface $em)
{
if (empty($this->originalEventListener)) {
throw new \Exception('can not undo remove, soft delete listener was not removed');
}
// re-add the removed listener back to the event-manager
$em->getEventManager()->addEventListener(self::EVENT_NAME, $this->originalEventListener);
}
}
usage:
$this->softDeleteFilter->removeSoftDeleteFilter($this->entityManager);
$this->entityManager->remove($entity);
$this->entityManager->flush();
$this->softDeleteFilter->undoRemoveSoftDeleteFilter($this->entityManager);
Just a small reminder.
When you want to hard delete entity with Gedmo Softdeletable you have to have hardDelete=true in the respective annotation, see:
#Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false, hardDelete=true)
EDIT: hardDelete=true is true by default
With this, you dont have to disable the listener/filter. If you have hardDelete=false, the double remove suggested above will not work.
Source:
https://github.com/Atlantic18/DoctrineExtensions/blob/v2.4.x/doc/softdeleteable.md
As in a former comment by qooplmao posted: A simple and working solution is:
// Remove an entity entirely from the DB (skip soft delete)
$this->entityManager->remove($entity);
$this->entityManager->flush();
// Just run it a second time :-)
$this->entityManager->remove($entity);
$this->entityManager->flush();
Just posted it again to give it a little bot more visibility as it works like a charme...
I have these two doctrine entity classes;
/** #ORM\Entity
* #ORM\Table(name="computer")
*/
class Computer extends Hardware
{
/**
* #ORM\OneToMany(targetEntity="LogicalDisk", mappedBy="computer", cascade={"persist", "remove"})
*/
protected $logicalDisks;
public function __construct()
{
$this->logicalDisks = new ArrayCollection();
}
public function addLogicalDisk($logicalDisk)
{
$this->logicalDisks[] = $logicalDisk;
$logicalDisk->setComputer($this);
}
public function clearLogicalDisks()
{
$this->logicalDisks->clear();
}
}
/** #ORM\Entity
* #ORM\Table(name="logical_disk")
*/
class LogicalDisk
{
/**
* #ORM\ManyToOne(targetEntity="Computer", inversedBy="logicalDisks")
* #ORM\JoinColumn(name="computer_id", referencedColumnName="id")
*/
protected $computer;
}
I'm trying to clear the existing collection, and then build up a new collection. However the old entities never get removed from the database.
$disks = $WbemServices->ExecQuery("Select * from Win32_LogicalDisk");
// Delete existing disk info for this host.
$computer = $service->findByDNSName($host, $domain);
$computer->clearLogicalDisks();
// loop through scanned disks and persist each one
foreach ($disks as $disk) {
$logicalDisk = new LogicalDisk();
$logicalDisk->setDeviceId($disk->DeviceId)
->setDescription($disk->Description)
->setFileSystem($disk->FileSystem)
->setCapacity($disk->Size)
->setFreeSpace($disk->FreeSpace);
$computer->addLogicalDisk($logicalDisk);
}
$service->persist($computer);
I have tried setting cascade={"persist", "remove"} on the logicalDisk property of the Computer entity, but this does not remove the items. I've also tried persisting the computer after clearing the ArrayCollection but the disk entities still do not get removed from the database.
I just need to know how to clear the ArrayCollection and then persist that change to the database, thus removing the unwanted entities.
I have a requirement where I want to test the below scenario with Selenium:
Open the xhtml page and the value in the datatable is 10.
Change the value in the database from 10 to 20
Click on the refresh button(Without opening the same xhtml page again) and value should be 20 now.
Below is what I am doing. But no success..
#Test
#InSequence(1)
public void addTestData() {
Warp.initiate(new Activity() {
#Override
public void perform() {
OurPage page = OurPage.on(selenium).withPath(SetupTestData.PATH);
page.addTestDataFor(REFRESH_SHOULD_WORK);
}
}).inspect(new Inspection() {
private static final long serialVersionUID = 1L;
});
}
#InSequence(2)
#Test
public void refreshShouldWork() {
Warp.initiate(new Activity() {
#Override
public void perform() {
CountryDetailsPage page = new CountryDetailsPage(selenium).withPath(CountryDetailsPage.PATH);
page.open();
System.out.println("*** PAGE OPENED ****");
waitGui().until().element(page.table(PROGRESSES_TABLE)).is().present();
assertThat(page.table.row(FIRST).cell(FIFTH).text(), is("10"));
// FIXME: Need to find out the way to change the value
page.refresh().click();
System.out.println("*** CLICKED REFRESH ****");
waitGui().until().element(page.table(PROGRESSES_TABLE)).is().present();
assertThat(page.table.row(FIRST).cell(FIFTH).text(), is("20"));
}
}).inspect(new Inspection() {
private static final long serialVersionUID = 1L;
#AfterPhase(RENDER_RESPONSE)
public void beforeRenderResponse() {
System.out.println("*** AFTER RENDER RESPONSE****");
}
#AfterPhase(Phase.APPLY_REQUEST_VALUES)
public void afterRenderResponse() {
System.out.println("*** AFTER APPLY REQUEST VALUES ****");
}
});
}
If you have any idea how can I achieve this, please let me know. Thanks
Being that Selenium automates only the UI, you should let a different technology handle the database. Selenium by itself is unable to connect to any database and change what you want.
You can use Java to do this. More specifically, use Java Database Connectivity (JDBC).
Here's an example that Vogella uses
try {
// this will load the MySQL driver, each DB has its own driver
Class.forName("com.mysql.jdbc.Driver");
// setup the connection with the DB.
connect = DriverManager
.getConnection("jdbc:mysql://localhost/feedback?"
+ "user=sqluser&password=sqluserpw");
// statements allow to issue SQL queries to the database
statement = connect.createStatement();
// resultSet gets the result of the SQL query
resultSet = statement
.executeQuery("select * from FEEDBACK.COMMENTS");
writeResultSet(resultSet);
// preparedStatements can use variables and are more efficient
preparedStatement = connect
.prepareStatement("insert into FEEDBACK.COMMENTS values (default, ?, ?, ?, ? , ?, ?)");
// "myuser, webpage, datum, summary, COMMENTS from FEEDBACK.COMMENTS");
// parameters start with 1
preparedStatement.setString(1, "Test");
preparedStatement.setString(2, "TestEmail");
preparedStatement.setString(3, "TestWebpage");
preparedStatement.setDate(4, new java.sql.Date(2009, 12, 11));
preparedStatement.setString(5, "TestSummary");
preparedStatement.setString(6, "TestComment");
preparedStatement.executeUpdate();
...
} catch (Exception e) {
throw e;
} finally {
close();
}
}
Update the above code to update the actual mysql field, and you'll be golden. Though I don't think this is a good test, as again, the UI should be making the change and Selenium should be detecting it. This might be a good candidate for an integration test. Not a Selenium test.
I want to implement auto save functionality.
I have a silverlight application, in which, we are sending data on server on clicking of a button. Now i don't want to click on that button, i want, my data should be post to server periodically with time interval of 20 or 30 seconds.
Plz provide me your valuable suggestion to how to implement this
I use this code to keep a session alive. It does the same thing that you are trying to do; automatically calls a service after specified regular intervals:
public Page()
{
InitializeComponent();
// Set up timer
System.Windows.Threading.DispatcherTimer dt =
new System.Windows.Threading.DispatcherTimer();
// Set to call every 5 minutes
dt.Interval = new TimeSpan(0, 0, 5, 0, 0);
// Set up event handler
dt.Tick += new EventHandler(dt_Tick);
// Start timer
dt.Start();
}
void dt_Tick(object sender, EventArgs e)
{
// Call web service
Ping();
}
void Ping()
{
WebTest.otsref.SilverlightServiceClient webService = new WebTest.SilverlightServiceClient();
webService.PingAsync();
}
I'm using QTableView in order to display the results of QSqlQueryModel. The data in DB is permanently changed so I run the same script every time and need to get updated data. The query is executed in another thread after which it returns the result to main thread.
void SqlThread::setNewScript(QString script)
{
QSqlQueryModel * sqlModel = new QSqlQueryModel();
this->script = script;
QSqlQuery query = QSqlQuery(this->script, db);
sqlModel->setQuery(query);
emit queryFinished(sqlModel);
}
void myTable::onQueryFinished(QSqlQueryModel * model)
{
QAbstractItemModel * oldModel = this->table->model();
QSortFilterProxyModel * sort = new QSortFilterProxyModel();
sort->setSourceModel(model);
this->table->setModel(sort);
delete oldModel;
}
The problem appeared when I've tried to introduce sorting using QSortFilterProxyModel. Since I did it my table haven't received any updated data.
I checked that QSqlQueryModel doesn't receive any updated data while running the same script in DBMS gives me new results.
If I don't use QSortFilterProxyModel the table is updated normally.
I dont know the rest of your code, but this may help.
void SqlThread::setNewScript(QString script)
{
//QSqlQueryModel * sqlModel = new QSqlQueryModel();
//It's better to implement your model as [QSortFilterSqlQueryModel][1]
QSortFilterSqlQueryModel * sqlModel = new QSortFilterSqlQueryModel();
this->script = script;
QSqlQuery query = QSqlQuery(this->script, db);
sqlModel->setQuery(query);
//use select to start query
sqlModel->select();
emit queryFinished(sqlModel);
}
/*
void myTable::onQueryFinished(QSqlQueryModel * model)
{
QAbstractItemModel * oldModel = this->table->model();
QSortFilterProxyModel * sort = new QSortFilterProxyModel();
sort->setSourceModel(model);
this->table->setModel(sort);
delete oldModel;
}
rest of can be corrected like that if you really wanna pass model to
the slot(this does not seems to be good idea as your model is already on the heap)*/
void myTable::onQueryFinished(QSortFilterSqlQueryModel * model)
{
table->setModel(model)
table->setSelectionMode(QAbstractItemView::SingleSelection);//other option(s) you like
table->setSortingEnabled(true);
}