JCR SQL2 query for an empty multivalued field - magnolia

In our scenario we have a (multivalued) category field on JCR:node and we want to query all nodes that do not have a current selection. In the JCR viewer the fields value is [] but I can't find any query to select nodes with this condition. We have tries:
SELECT * FROM [mgnl:page] as p WHERE p.[categories]=''
or
SELECT * FROM [mgnl:page] as p WHERE p.[categories]=[]
or
SELECT * FROM [mgnl:page] as p WHERE p.[categories] is null
But they aren't working or don't select the proper result. How can we write a query selecting these nodes?

From the JSR 283:
5.10.3 Value Length
The length of a value in a single-value property, as defined in ยง3.6.7 Length of a Value, is returned by long Property.getLength()
Similarly, the method long[] Property.getLengths() is used to get an array of the lengths of all the values of a multi-value property.
From the JavaDocs:
/**
* Returns an array holding the lengths of the values of this (multi-value)
* property in bytes where each is individually calculated as described in
* {#link #getLength()}.
* <p>
* Returns a <code>-1</code> in the appropriate position if the
* implementation cannot determine the length of a value.
*
* #return an array of lengths
* #throws ValueFormatException if this property is single-valued.
* #throws RepositoryException if another error occurs.
*/
public long[] getLengths() throws ValueFormatException, RepositoryException;
Unfortunately, this does not make it clear what the result of LENGTH([multivaluedProperty)] is in a SQL2 query.
Though, after some manual testing, it seems that the LENGTH operand returns some number smaller than 0. Therefore, you could try
select * from [nt:base] where LENGTH([multivaluedProperty]) < 0
Let me know whether this works for you :)

Related

Firestore SnapshotOptions = { serverTimestamps: 'previous' }, what value it return if there is no previous value?

export declare interface SnapshotOptions {
/**
* If set, controls the return value for server timestamps that have not yet
* been set to their final value.
*
* By specifying 'estimate', pending server timestamps return an estimate
* based on the local clock. This estimate will differ from the final value
* and cause these values to change once the server result becomes available.
*
* By specifying 'previous', pending timestamps will be ignored and return
* their previous value instead.
*
* If omitted or set to 'none', `null` will be returned by default until the
* server value becomes available.
*/
readonly serverTimestamps?: 'estimate' | 'previous' | 'none';
}
It stated there that previous returns the previous timestamp when pending, what if this is the first time it is written into the database and no previous value?
what will it return?
If you use previous without any timestamps being available in the server already than this timestamp will be treated as an "unresolved timestamp" and you get the a null returned value, therefore same behavior as having it omitted or set to none.

Reducing unnecessary joins in Doctrine

For simplicity sake let there be 2 entities in Symfony. The first one is called Job and the second one Field (category for Job). Each job can belong to multiple fields. Job is aware of it's fields, while the Field entity knows nothing about jobs.
// Job.php
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Field")
* #ORM\JoinTable(name="job_to_fields",
* joinColumns={#ORM\JoinColumn(name="job_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="field_id", referencedColumnName="id")}
* )
*/
private $fields;
When we want to load all jobs for fields [1, 2, 3], I'd expect something like
SELECT j.*
FROM job j
INNER JOIN job_to_fields jtf ON j.id = jtf.job_id
WHERE /* some other parameters */jtf.field_id IN (1, 2, 3)
In reality Doctrine constructs this SQL statement:
SELECT j.*
FROM job j
INNER JOIN job_to_fields jtf ON j.id = jtf.job_id
INNER JOIN field f ON f.id = jtf.field_id
WHERE /* some other parameters */f.id IN (1, 2, 3)
The second join (to the field table) seams unnecessary. Is there a way to remove this/tell doctrine not to do this?
In theory Doctrine should know about the relation of f.id and jtf.field_id, as it's using them in a join.
This is correct behavior because without that join calling getFields() on a Job object would not have access to the data to display.
You might be able to affect this by using lazy fetch on your $fields annotation, but if you ever call getFields() it will wind up running further queries to get the data anyway.
#ORM\ManyToMany(targetEntity="App\Entity\Field", fetch="EXTRA_LAZY")
But, unless you are addressing a specific issue, I'd let it ride. This is ORM doing what ORM does.

How to create constraint for limiting max childs

Let's say I have two entities Bus and People with a relation OneToMany between them.
Bus can hold a maximum of 10 persons.
How to create a constraint to control this?
For example:
* #MyAssert\ParentMaxChild(max=10)
* #ORM\ManyToOne(targetEntity="Webface\CharacterBundle\Entity\Bus", inversedBy="wac")
* #ORM\JoinColumn(name="bus_id", referencedColumnName="id", nullable=false)
private $bus;
Use the Count constraint.
In your Bus class, add the constraint in the Person annotation:
/**
* ... Rest of the annotation ...
* #Assert\Count(
* max = "10",
* maxMessage = "Bus can hold a maximum of 10 persons."
* )
*/
protected $persons;
Note that you can specify a min parameter and the according message.

Symfony2 store database schema information in database tables

I need to have my database schema information stored in the database.
I already have a table called db_entity which stores the entity name, namespace and other options.
Related to this table I need to have a table entity_attributes which will have the entity_id,attribute_name,attribute_type,required etc.
Creating the schema structure is easy but inserting all the fields from all my entites in the db would be a tedious work.
Is there any way I can create a script that will parse all my entities annotations, allowing me to create all the fields into my database table?
The best would be to write a similar command to doctrine:schema:update that would update my table schema.
Thank you.
The doctrine metadata class http://www.doctrine-project.org/api/orm/2.2/source-class-Doctrine.ORM.Mapping.ClassMetadataInfo.html contains a public property that could be exactly what you need:
222: /**
223: * READ-ONLY: The field mappings of the class.
224: * Keys are field names and values are mapping definitions.
225: *
226: * The mapping definition array has the following values:
227: *
228: * - <b>fieldName</b> (string)
229: * The name of the field in the Entity.
230: *
231: * - <b>type</b> (string)
232: * The type name of the mapped field. Can be one of Doctrine's mapping types
233: * or a custom mapping type.
234: *
235: * - <b>columnName</b> (string, optional)
236: * The column name. Optional. Defaults to the field name.
237: *
238: * - <b>length</b> (integer, optional)
239: * The database length of the column. Optional. Default value taken from
240: * the type.
241: *
242: * - <b>id</b> (boolean, optional)
243: * Marks the field as the primary key of the entity. Multiple fields of an
244: * entity can have the id attribute, forming a composite key.
245: *
246: * - <b>nullable</b> (boolean, optional)
247: * Whether the column is nullable. Defaults to FALSE.
248: *
249: * - <b>columnDefinition</b> (string, optional, schema-only)
250: * The SQL fragment that is used when generating the DDL for the column.
251: *
252: * - <b>precision</b> (integer, optional, schema-only)
253: * The precision of a decimal column. Only valid if the column type is decimal.
254: *
255: * - <b>scale</b> (integer, optional, schema-only)
256: * The scale of a decimal column. Only valid if the column type is decimal.
257: *
258: * - <b>unique (string, optional, schema-only)</b>
259: * Whether a unique constraint should be generated for the column.
260: *
261: * #var array
262: */
263: public $fieldMappings = array();

Duplicate Record Created Using PHP Services

Under what circumstances will the following line create two records instead of one?
The line only runs once, I traced the program to make sure.
createIndcsfResult.token = indcsfService.createIndcsf(indCSF2);
Standard Service
/**
* Returns the item corresponding to the value specified for the primary key.
*
* Add authorization or any logical checks for secure access to your data
*
*
* #return stdClass
*/
public function createIndcsf($item) {
$stmt = mysqli_prepare($this->connection, "INSERT INTO $this->tablename (indcsf_name, indcsf_yourcsf_id, indcsf_status) VALUES (?, ?, ?)");
$this->throwExceptionOnError();
mysqli_stmt_bind_param($stmt, 'sis', $item->indcsf_name, $item->indcsf_yourcsf_id, $item->indcsf_status);
$this->throwExceptionOnError();
mysqli_stmt_execute($stmt);
$this->throwExceptionOnError();
$autoid = mysqli_stmt_insert_id($stmt);
mysqli_stmt_free_result($stmt);
mysqli_close($this->connection);
return $autoid;
}

Resources