Does Doctrine2 support the ability to update an association when it is changed from the inverse side? And if not out of the box, is there a plugin/extension I can use to cover this behavior?
Here is an example of what I have:
Organization
/**
* #Id
* #Column(type="integer")
*/
protected $id
/**
* #ManyToOne(targetEntity="Organization", inversedBy="children", cascade={"persist"})
* #JoinColumn(name="parent_org_id", referencedColumnName="id")
*/
protected $parent;
/**
* #OneToMany(targetEntity="Organization", mappedBy="parent", cascade={"persist"})
*/
protected $children;
No. Doctrine 2 tracks associations through the owning side and as it tries to have minimal effect on the behavior of your entities, it wouldn't want to add this kind of functionality.
The standard way to track changes on the inverse side is to ensure that they remain in sync by adding logic to your entities that updates the owning side when making changes on the inverse.
In your example, you could have addChild, removeChild and setParent functions that do something like this:
public function addChild(Organization $child)
{
$this->children[] = $child;
$child->setParent($this); // < update the owning side
}
public function removeChild(Organization $child)
{
$this->children->removeElement($child);
$child->setParent(null); // < update the owning side
}
public function setParent(Organization $parent = null)
{
$this->parent = $parent;
}
You can see that now there is a new problem, you must always use the addChild/removeChild functions (i.e. make changes on the inverse side) for the owning side remain in sync (or sync it yourself, as the caller). This leads to you having to create a policy, either callers must always update on the owning side, or the inverse side.
You could make the setParent function update the inverse side also, but you must be very careful as that can easily lead to infinite recursion:
public function addChild(Organization $child)
{
$this->children[] = $child;
// safely update the owning side
if ($child->getParent() != $this) {
$child->setParent($this);
}
}
public function removeChild(Organization $child)
{
$this->children->removeElement($child);
// safely update the owning side
if ($child->getParent() == $this) {
$child->setParent(null);
}
}
public function setParent(Organization $parent = null)
{
$oldParent = $this->parent;
$this->parent = $parent;
// update the inverse side
if ($oldParent) {
$oldParent->removeChild($this); // will not call setParent
}
if ($this->parent) {
$this->parent->addChild($this); // will not call setParent
}
}
Apart from the added complexity, this scheme is not ideal when for example moving lots of children from one parent to another, because removeChild takes linear time, creating a O(n^2) running time for the move.
Related
I am having a QGraphicsView which contains some QGraphicsItem I have a feature (Hide Item) which on mouse right click, hide desired QGraphicsItem(Rectangle) and its connected polylines. I have a Undo-Redo feature also.
Undo - It should cancel the effect of last command executed and show
previous transformation.
Redo - It will undo the previous Undo.
To implement this Undo-Redo feature I have used Command pattern. I have implemented Undo-Redo feature for ZoomIn-ZoomOut.
Question is : I dont know how to implement Undo-Redo for Hide feature. Means what to push into stack, what to pull ?
Below Undo-Redo code is for ZoomIn-ZoomOut feature. (It is just for reference that I want to implement Hide feature something like this. )
myCommand.c
class myCommand: public QUndoCommand
{
public:
myCommand();
myCommand(double scale, QGraphicsScene* scene,QGraphicsView* view);
private:
QGraphicsItem* mItem;
QGraphicsScene* mScene;
QGraphicsView* mView;
double scaleFactor;
void undo();
void redo();
}
myCommand.cpp
myCommand::myCommand(double scale, QGraphicsScene *scene,QGraphicsView* view): mScene(scene),
mView(view),scaleFactor(scale)
{}
void guiCommand::undo()
{
mView->scale(1/scaleFactor,1/scaleFactor);
}
void myCommand::redo()
{
mView->scale(scaleFactor,scaleFactor);
}
myView.cpp
void myView::ZoomIn()
{
double scaleFactor = 1.1;
view->scale(scaleFactor,scaleFactor);
myCommand* command1 = new myCommand(scaleFactor,scene,view);
undoStack->push(command1);
}
myView.h
public:
QUndoStack* undoStack;
New addition :
void myRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
vPtr = this->getPtr();
if(vPtr->isVisible == false)
this->hide();
else
{
this->show();
qDebug()<<"Undo Rect";
}
}
myCommand is :
myCommand* command3 = new myCommand(isRectHiddden,vPtr,GraphName);
undoStack->push(command3);
It should be very simple given the fact that you already successfully implemented zoom-in/zoom-out.
class HideItemCommand: public QUndoCommand
{
public:
explicit HideItemCommand(QGraphicsItem *item);
private:
QGraphicsItem* mItem;
void undo();
void redo();
}
HideItemCommand::HideItemCommand(QGraphicsItem *item): mItem(item)
{}
void HideItemCommand::undo()
{
mItem->show();
}
void myCommand::redo()
{
mItem->hide();
}
void myView::hideItem(QGraphicsItem* item)
{
item->hide();
auto cmd = new HideItemCommand(item);
undoStack->push(cmd);
}
So this is very simple. BUT!!! Now I am going to think one or two steps ahead. You asked only about showing/hiding undo/redo which can be implemented using the code which I suggested. But you are probably developing some drawing app so I guess that sooner or later you will want also add-item or remove-item undoable/redoable commands. And then the code which I wrote will not suffice any more. The reason is that holding item by pointer will not work any more if you remove and then add again the item using undo/redo. After redoing of remove operation, the pointer to the newly re-created object will be different the the pointer to the corresponding object which you had deleted earlier, so the item kept in HideCommand via its pointer will be invalid.
To solve this problem of invalid pointers, you need to invent some other way of recording what items you have in your scene. For example some UUID or just a sequence of integers (which is what I would do), lets call it item ID. And then keep a two-way map of these item IDs and corresponding pointers, so that you are able to translate ID to the item pointer, there and back.
Then when you create an item via some AddItemCommand you create the item and generate its ID and store the relation between the ID and the pointer to the map. You put record of this ID in the undo command. And for all other commands which will need to refer to that item (e.g. that HideCommand) you will use the ID instead of the pointer. This will allow you put all commands to the stack, use stable IDs and not volatile pointers which may change as you undo/redo adding or deleting of objects. Also RemoveItemCommand will record the ID of the removed object and if undone, the new item will be created (i.e. a new, different pointer) but with the old, known ID. So other commands referencing this ID will still be valid.
I hope I managed to explain this well. In fact it is not that difficult. You just need to understand that pointers will change over time if you add or remove items with undo/redo, but IDs can stay the same. Therefor you need to keep IDs in your commands and not pointers. This will of course change the code which I wrote a bit. But I believe you are able to adjust it from using pointers to using IDs by yourself once you implement the ID <-> pointer mapping in your app.
When using QtConcurrent::run to run code in the background from a UI the
QFuture::then(QObject *context, Function &&function) can be used to update the UI because you can pass the window object as context to make function execute on the GUI thread. This is very convenient however there is one problem. When the window is closed and it is deallocated before the background task completes the program will crash when the task completes because the context passed to then is no longer valid.
Is there an easy way to prevent this problem? I know a QFutureWatcher can be used but that object would need to be added to the window class and one would be needed for every asynchronous task the window can execute which is cumbersome.
One simple option would be to use a QPointer to track/monitor the QWidget of interest. A copy of the QPointer can be captured by whatever lambdas or functors are used by QtConcurrent::run or QFuture::then.
/*
* Set up the QWidget that we need to monitor.
*/
auto w = std::make_unique<QLabel>("Working...");
w->show();
/*
* Create a QPointer that that we can use to check the validity of 'w'.
*/
auto qp = QPointer<QWidget>(w.get());
/*
* We can now bind qp into any lambdas.
*/
auto f = QtConcurrent::run(
[]
{
/* Time consuming stuff goes here. */
})
.then(
qApp,
[qp]
{
if (qp) {
/*
* qp reports that 'w' is still valid so do whatever we
* need to do with it.
*/
qp.data()->setText("Done");
} else {
/*
* 'w' is no longer valid.
*/
}
});
[Note: the above is untested as I don't have Qt6 on the box I'm working on right now.]
When the base value of an attribute changes, there is UAttributeSet::PostGameplayEffectExecute() available to access the (new) value and GameplayEffect with its context. I'm using this to print the changed value to UI (this is also done in ActionRPG).
Is there something similar available for the current value of an attribute? How to notify UI, when FGameplayAttributeData::CurrentValue is updated?
Though UAttributeSet::PreAttributeChange() is called on every value update, it doesn't provide any context so it is not possible to access the UI from there (events broadcasted by FAggregator also don't fit).
It is possible to use a GameplayCue instead, to set the value of FGameplayAttributeData::CurrentValue within the UI (the cue is triggered by the GameplayEffect who sets the current value). This is possible by deriving from a GameplayCueNotifyActor and use its events OnExecute and OnRemove. However, instantiating an actor just to update UI seems to be a waste of resources.
It is also possible to fetch the information using the UI itself (calling a function which accesses the attribute each tick or with a timer), but in comparison to event driven UI update, this is also wasteful.
The GameplayAbilitySystem has UAbilitySystemComponent::GetGameplayAttributeValueChangeDelegate() which returns a callback of type FOnGameplayAttributeValueChange that is triggered whenever an attribute is changed (base value or current value). This can be used to register a delegate/callback, which can be used to update the UI.
Minimal example
In MyCharacter.h
// Declare the type for the UI callback.
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAttributeChange, float, AttributeValue);
UCLASS()
class MYPROJECT_API MyCharacter : public ACharacter, public IAbilitySystemInterface
{
// ...
// This callback can be used by the UI.
UPROPERTY(BlueprintAssignable, Category = "Attribute callbacks")
FAttributeChange OnManaChange;
// The callback to be registered within AbilitySystem.
void OnManaUpdated(const FOnAttributeChangeData& Data);
// Within here, the callback is registered.
void BeginPlay() override;
// ...
}
In MyCharacter.cpp
void MyCharacter::OnManaUpdated(const FOnAttributeChangeData& Data)
{
// Fire the callback. Data contains more than NewValue, in case it is needed.
OnManaChange.Broadcast(Data.NewValue);
}
void MyCharacter::BeginPlay()
{
Super::BeginPlay();
if (AbilitySystemComponent)
{
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(MyAttributeSet::GetManaAttribute()).AddUObject(this, &MyCharacterBase::OnManaUpdated);
}
}
In MyAttributeSet.h
UCLASS()
class MYPROJECT_API MyAttributeSet : public UAttributeSet
{
// ...
UPROPERTY(BlueprintReadOnly, Category = "Mana", ReplicatedUsing=OnRep_Mana)
FGameplayAttributeData Mana;
// Add GetManaAttribute().
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(URPGAttributeSet, Mana)
// ...
}
Example for updating the UI via the EventGraph of the character blueprint, which derived from MyCharacter. UpdatedManaInUI is the function which prints the value to the UI.
Here, UpdatedManaInUI retrieves the value by itself. You might want to use the AttributeValue of OnManaChange.
I was just playing around with the "state design pattern" and had a couple of questions on how exactly errors are handled in a state machine. Let us take the case below
class state_machine
{
private:
state state1;
state state2;
public:
}
class state
{
private:
state_machine* m_state_machine; /** Will pass the pointer to states **/
public:
void perform_state1_action();
void perform_state2_action();
}
class state1: public state
{
public:
void perform_state1_action()
{
/**
Functionality
**/
}
void perform_state2_action(); // Have nothing to do for this function
}
class state2: public state
{
public:
void perform_state2_action()
{
/**
Functionality
**/
}
void perform_state1_action(); // Have nothing to do for this function
}
My question is how do I gracefully handle the case where we call perform_state2_action when its in state1. Do I write a base function implementation with nothing or maybe error logging functionality?
This design pattern requires you to provide public methods that are available for every state. If you come across a situation that you feel an urge to add an action that is valid only for one of them, it could mean one of the following:
You should make it private and call it from more general, public method(s), which can be implemented for all of your states
This method should be moved outside of the state machine because it is not related to the state
This is a specific case where empty implementation is a correct behaviour (so no error log needed)
You have chosen wrong design pattern
I decided to use the state design pattern with minor changes:
Use a generic name for a function like "do_task" and use this to call the needed private functions.
This provided the benefits of the state design pattern at the same time preventing creation of surplus absolute virtual functions
I'm learning CQRS recently, so I started a sample project with axon-framework(A java CRQS framework).
According to the quick start, I got this below:
public class CreditEntryUnitTests {
private FixtureConfiguration fixture;
#Before
public void setUp() throws Exception {
fixture = Fixtures.newGivenWhenThenFixture(CreditEntry.class);
}
#Test
public void creditEntryCreated() throws Throwable {
final Long entryId = 1L;
final int amount = 100;
fixture.given().when(new CreateCreditEntryCommand(entryId, amount))
.expectEvents(new CreditEntryCreatedEvent(entryId, amount));
}
#Test
public void creditEntryMadeEffective() throws Throwable {
final Long entryId = 1L;
final int amount = 100;
final Date start = nov(2011, 12);
final Date end = nov(2012, 12);// a year effective period
fixture.given(new CreditEntryCreatedEvent(entryId, amount))
.when(new MakeCreditEntryEffectiveCommand(entryId, start, end))
.expectEvents(new CreditEntryMadeEffectiveEvent(entryId, start, end));
}
//omitted support methods
}
public class CreditEntry extends AbstractAnnotatedAggregateRoot {
#AggregateIdentifier
private Long id;
private int amount;
private Date effectiveDateRangeStart;
private Date effectiveDateRangeEnd;
private Status status;
#CommandHandler
public CreditEntry(CreateCreditEntryCommand command) {
apply(new CreditEntryCreatedEvent(
command.getEntryId(), command.getAmount()));
}
#EventHandler
public void on(CreditEntryCreatedEvent event) {
this.id = event.getEntryId();
this.amount = event.getAmount();
this.status = Status.NEW;
}
#CommandHandler
public void markCompleted(MakeCreditEntryEffectiveCommand command) {
apply(new CreditEntryMadeEffectiveEvent(
command.getEntryId(), command.getStart(), command.getEnd()));
}
#EventHandler
public void on(CreditEntryMadeEffectiveEvent event) {
this.effectiveDateRangeStart = event.getStart();
this.effectiveDateRangeEnd = event.getEnd();
this.status = Status.EFFECTIVE;
}
public CreditEntry() {}
public enum Status {
NEW, EFFECTIVE, EXPIRED
}
}
The test code drives me written the domain model and integration code with axon-framework but it doesn't cover what side effect the event made. Where did I test them? e.g. when made effective the credit entry's status should be effective. Should I create a CreditEntry instance in other test methods and test by calling specific on(...Event event) method?
And one more question is: where should I put business validation logic? In command handler method? Assuming if the CreditEntry can not be made effective again given it is effective already.
#CommandHandler
public void markCompleted(MakeCreditEntryEffectiveCommand command) {
if (is(NEW)) {
apply(new CreditEntryMadeEffectiveEvent(
command.getEntryId(), command.getStart(), command.getEnd()));
} else {
throw new IllegalStateException(.......);
}
}
Any idea is appreciate, thank you.
On your first question:
Do you mean by side effect the internal state of your aggregate object? The Given-When-Then fixture test treat the aggregate as a kind of black box. So indeed, there is no real need to test the internal state. It is only important that the right events are applied.
So for example, you might even end up with aggregates without any fields (expect the ID) as your decision logic does not depend on any internal state. As a rule of thumb, I only save data transported in an event in the aggregate object if I need it later to decide which events to apply or if it changes the data applied in an event.
If you keep that in mind, you don't really have to test the internal state. You simply configure an aggregate with specific events in the given clause (build up some state) and then apply a command. If the correct events come out... you're done.
On your second question:
Business validation should go in the command handler. So everything should be validated before the applymethod is called. One reason for this: Imagine a system in which the validation logic changes over the life time, but you have to deal with old data which was entered when the system was introduced. If the validation would be in the event handler and the validation is not the same as when the event was first introduced, loading your aggregate from the events might fail as the "old" data does not match to the current validation logic.