I'm not able to drop a property from a class. The error says that the property can not be found in class. But the property is there for sure.
I've tried to drop the property with command 'DROP PROPERTY VResearchInstitution.turnover' and also from OrientDB studio.
I want to drop the property from that class and add it back with other Data Type, from STRING to EMBEDDEDLIST. I know there should be a way to ALTER property and modify the type, but I'm not able to do that too, that's why I'm trying to delete it and add it back.
I noticed that only Node/Vertex with SuperClass seted has this behaviour. If someone has a better answer please let me know.
You are probably making a small mistake somewhere else, something like a typo.
Consider the following code, which works without errors (you can try yourself):
/* Let's create a class TEST that has V as superclass */
CREATE CLASS TEST EXTENDS V
/* Let's create a class EXAMPLE that has TEST as superclass */
CREATE CLASS EXAMPLE EXTENDS TEST
/* Let's create a property */
CREATE PROPERTY EXAMPLE.Name STRING
/* Now let's delete the property */
DROP PROPERTY EXAMPLE.Name
/* EXAMPLE.name has been deleted successfully */
/* Now let's try altering the property */
CREATE PROPERTY EXAMPLE.Name STRING
ALTER PROPERTY EXAMPLE.Name MANDATORY TRUE
/* EXAMPLE.name has been altered successfully */
This works as expected. Beware of the following things when dropping properties:
OrientDB is case-sensitive! In the above example, DROP PROPERTY EXAMPLE.name would give an error, so make sure that your query doesn't contain any typo's.
Dropping properties does not delete data. Consider the following:
/* Let's add a vertex */
CREATE VERTEX EXAMPLE SET Name = 'a'
/* Now let's try deleting the property */
DROP PROPERTY EXAMPLE.Name
/* Now let's query the vertex */
SELECT FROM EXAMPLE WHERE Name = 'a'
The result will still contain the property Name = 'a' because dropping the property of a class only changes the schema of the class, but since OrientDB's classes are schema-less, your data is retained.
Hope that helps you find the bug.
Related
I am following this documentation: https://docs.typo3.org/m/typo3/book-extbasefluid/10.4/en-us/5-Domain/2-implementing-the-domain-model.html
The 'Organization' model defines setters and a method "addContact"
/**
* Adds a contact to the organization
*
* #param Person The contact to be added
* #return void
*/
public function addContact(Person $contact)
{
$this->contacts->attach($contact);
}
I created an extbase model myself, which requires records from an objectstorage. But i figured it out, that I could render records from an objectstorage in fluid, without defining "add{property}" and "set{property} methods. What are the purpose of these methods? When and where are they called?
Setter methods (and adder for ObjectStorages) are not needed by the framework. I'd recommend not adding them if you do not have the use case of setting a value programmatically.
Generally speaking you should not add code that you dont need.
Extbase itself will use reflection to gather and set properties that match database columns.
Setters are for fields that have a representation in the database.
You can add more properties to the models which are i.e. calculated or get the values somewhere else from that don't have setter methods.
Those properties you can access in fluid templates as long as they have also a declaration in the model.
Concerning the method addContact that's one property with probably 4 methods:
getContact (is singular but can have several)
setContact (is singular but can have several)
addContact (adds one contact to the $contact)
removeContact (removes one contact from the $contact)
So this property is still connected / related to the database, just that it's a foreign table as it's foreign model too.
$contact in your case is likely of type \TYPO3\CMS\Extbase\Persistence\ObjectStorage which is like an array iterable but just as object.
I have an object appointment with a property expertises of type \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Vendor\Extname\Domain\Model\Expertise>.
Additionally one important property of Expertise is the bool checked.
What I want to do in my AppointmentController is:
In the first action: Empty the appointment's property expertises (not set it to NULL, I just want an empty ObjectStorage that I can add something to later)
In the second action: Fill appointment with expertises (from a different object) whose property checked equals true
To start out with the emptying I looked at the answer from here but it didn't work for me.
This is what I tried:
$appExp = $appointment->getExpertises();
foreach ($appExp as $exp) {
$appExp->detach($exp);
}
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($appointment);
But it shows that all expertises are still in appointment.
In the second action I do this:
foreach ($expertises as $expertise) {
if ($expertise->getChecked()) {
$appointment->addExpertise($expertise);
}
}
It works, but I wonder if there's an easier "filter" function that can automatically filter the checked value and return an ObjectStorage object. Because this way I could just use setExpertises() and the old ones would get overwritten which would make the first step unnecessary.
So does someone have an idea for the emptying and filtering of ObjectStorage objects?
I looked a bit into the ObjectStorage Class reference but there's no obvious function that empties it (removeAll ist just for objects contained in another storage from the current storage) and no filter function either.
There is an easy way to remove all objects from the object storage:
$appointment->getExpertises()->removeAll($appointment->getExpertises());
As for filtering: as you already noticed, you have to do it yourself. I would implement such functions like getActiveExpertises in the Model, because it fits there much better than in a controller.
The setters in ExtbaseObjects that refer to ObjectStorages have an optional parameter that defaults to null. Just call the setter without a parameter. You don't have to waste performance by instanciating an empty StorageObject.
$appointment->setExpertises();
I have a class who's main purpose revolves around a temp table. I want to make a constructor that takes an identical temp table as input.
So far the compiler chokes on any attempt to pass a temp table as a input parameter. If I use a table handle instead, it works. But I'd rather not copy from a dynamic table to a static one.
Progress wants the tables to match up at compile time, but I know they'll be the same - the're defined in a .i file.
Is there an easy way to line up the tables, or am I stuck parsing it out one field at a time?
Works like a charm to me.
CLASS Test.TTOO.TempTableWrapper:
{Test/TTOO/ttCustomer.i}
CONSTRUCTOR PUBLIC TempTableWrapper (TABLE ttCustomer):
FOR EACH ttCustomer:
DISPLAY ttCustomer.CustNum ttCustomer.Name .
END.
END CONSTRUCTOR.
END CLASS.
and the caller:
ROUTINE-LEVEL ON ERROR UNDO, THROW.
USING Test.TTOO.* FROM PROPATH.
DEFINE VARIABLE oWrapper AS TempTableWrapper NO-UNDO .
{Test/TTOO/ttCustomer.i}
/* *************************** Main Block *************************** */
CREATE ttCustomer.
ASSIGN ttCustomer.CustNum = 42
ttCustomer.Name = "It works" .
oWrapper = NEW TempTableWrapper(TABLE ttCustomer ) .
You can also pass the temp-table by-ref:
oWrapper = NEW TempTableWrapper(TABLE ttCustomer BY-REFERENCE) .
However, then the temp-table data is only availalbe during the constructor as BY-REFERENCE calls "overlap" the temp-table within the callee only for the duration of that call.
For permanent "BY-REFERENCE", use the BIND keyword on the call and the paramter - in which case the callee must define the temp-table as REFERENCE-ONLY.
Note, it's not required (although recommended at least by me) to define the temp-tables in include files. At runtime and compile time, the schemas just need to match.
When the compiler does not like your call, delete the classes r-code and recompile.
So I have a model like this:
class MyClass
{
public $customer = null;
public $address = null;
}
And a form like this:
class MyForm extends CFormModel
{
public $customer = null;
public $address = null;
/**
* Declares the validation rules.
*/
public function rules()
{
return array(
array('customer, address', 'required'),
array('verifyCode', 'captcha', 'allowEmpty'=>!CCaptcha::checkRequirements()),
);
/**
* Declares customized attribute labels.
* If not declared here, an attribute would have a label that is
* the same as its name with the first letter in upper case.
*/
public function attributeLabels()
{
return array(
'verifyCode'=>'Verification Code',
);
}
}
What I would like to do, is extend the model in my form, but you can't do multiple object inheritance in PHP.
How would I do this, so as to avoid duplicating all of the field properties of model in form?
Use of Component Behavior
A component supports the mixin pattern and can be attached with one or several behaviors. A behavior is an object whose methods can be 'inherited' by its attached component through the means of collecting functionality instead of specialization (i.e., normal class inheritance). A component can be attached with several behaviors and thus achieve 'multiple inheritance'.
Behavior classes must implement the IBehavior interface. Most behaviors can extend from the CBehavior base class. If a behavior needs to be attached to a model, it may also extend from CModelBehavior or CActiveRecordBehavior which implements additional features specifc for models.
To use a behavior, it must be attached to a component first by calling the behavior's attach() method. Then we can call a behavior method via the component:
// $name uniquely identifies the behavior in the component
$component->attachBehavior($name,$behavior);
// test() is a method of $behavior
$component->test();
An attached behavior can be accessed like a normal property of the component. For example, if a behavior named tree is attached to a component, we can obtain the reference to this behavior object using:
$behavior=$component->tree;
// equivalent to the following:
// $behavior=$component->asa('tree');
A behavior can be temporarily disabled so that its methods are not available via the component. For example,
$component->disableBehavior($name);
// the following statement will throw an exception
$component->test();
$component->enableBehavior($name);
// it works now
$component->test();
It is possible that two behaviors attached to the same component have methods of the same name. In this case, the method of the first attached behavior will take precedence.
When used together with events, behaviors are even more powerful. A behavior, when being attached to a component, can attach some of its methods to some events of the component. By doing so, the behavior gets a chance to observe or change the normal execution flow of the component.
A behavior's properties can also be accessed via the component it is attached to. The properties include both the public member variables and the properties defined via getters and/or setters of the behavior. For example, if a behavior has a property named xyz and the behavior is attached to a component $a. Then we can use the expression $a->xyz to access the behavior's property.
More reading:
http://www.yiiframework.com/wiki/44/behaviors-events
http://www.ramirezcobos.com/2010/11/19/how-to-create-a-yii-behavior/
I am using symfony 1.4 with Doctrine. I have built a form which uses a table that has the Versionable behaviour. As expected, Versionable creates a new version of the row every time the form is submitted and saved. My problem is that I would like to prevent it doing so if the actual values submitted are not any different from the original values put into the form via the edit action.
I know that I can do this with javascript relatively easily. I'm just curious as to whether symfony or Doctrine have this functionality already, and how it is used if so. It just seems like something that symfony would have a method for, which could be checked right before $form->save() is called. Am I dreaming or perhaps missing something obvious?
You can use the DoctrineRecord::getModified() function which returns an array of the modified fields and associated values from an overridden save() function or in a listener (preSave would be the best I guess).
If the new values are not any different, you can bypass the actual call to save(), so no new version is created.
The comment for the save() method of the Doctrine_Record is
/**
* applies the changes made to this object into database
* this method is smart enough to know if any changes are made
* and whether to use INSERT or UPDATE statement
*
* this method also saves the related components
*
* #param Doctrine_Connection $conn optional connection parameter
* #throws Exception if record is not valid and validation is active
* #return void
*/
so first, you should check whether it does not already work.
If not, Doctrine_Record has a isModified() method you could use. If the bind() method of the form object modifies the object in the form which should at first contain the default values, then this method should return true.
If you don't want to override save() method or implement a listener as jaudette suggested you can instead stay with form binding:
$form->bind($values);
if ($form->isValid()) {
$form->updateObject();
$changes = $form->getObject()->getModified();
// save to database if desired
$form->save();
}
The object will not be saved to database by calling $form->updateObject(), but the actual php object is changed.
Also note that you might have to call getModified() on each related object if you have embedded subforms.