Doctrine Entity findBy Many to Many - symfony1

I have a many to many relationship between products and colours.
What I am trying to do is find products by their colours.
eg)
$colours = $em->getRepository('Xxxxx\XxxxxBundle\Entity\Colour')->findBy(array('name'=>'red');
$products = $em->getRepository('Xxxxx\XxxxxBundle\Entity\Product')->findBy(array('colours'=>$colours));
This is my Yaml config:
Xxxxx\XxxxxBundle\Entity\Product:
type: entity
manyToMany:
colours:
targetEntity: Colour
joinTable:
name: Product_Colour
joinColumns:
product_id:
referencedColumnName: id
inverseJoinColumns:
colour_id:
referencedColumnName: id
.
Xxxxx\XxxxxBundle\Entity\Colour:
type: entity
id:
id:
type: integer
generator:
strategy: AUTO
fields:
hex:
type: string
length: 320
name:
type: string
length: 320
The error message I am getting is:
Notice: Undefined index: joinColumns in /home/xxx/public_html/products/vendor/doctrine/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php line 1217
Would someone be able to shine some light on why this is not working.

I know this is an old question, but if anyone else arrives here via Google (like I did), I had to eschew the findBy and use DQL in the repository:
$products = $em->getRepository('Vendor\Bundle\Entity\Product')->findByColours($colours);
And in the repository:
public function findByColours($colours)
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb ->select(array('p'))
->from('VendorBundle:Product', 'p')
->join('p.colours', 'c', 'WITH', $qb->expr()->in('c.id', $colours));
$result = $qb->getQuery()->execute();
return $result;
}
You may need to change the join based on what $colours is. This is assuming it's an array of colour IDs. If it's a string you can forgo the in() or if it's an array of strings you'll need to bind the strings as parameters (see the following link). Clarification on expr() and such is in the Doctrine docs
I don't know why Undefined index: joinColumns occurs, but this is a method to side-step it altogether. Hopefully someone can clarify as to the error, as my solution adds extra work to the Many to Many relationship.

Related

Apollo ios codegen generates optional values

I'm trying with all the latest version of apollo-ios but i'd like to solve this one lingering problem: I keep getting optional values (see image below).
Here's what I've explored (but still can't find whyyy)
When I created the table, Nullable is false. Then, I create a view which is for public to access it.
With apollo schema:download command, here's the generated json: schema.json
With graphqurl command, here's the generated schema.graphql: schema.graphql. Here's the snippet.
"""
columns and relationships of "schedule"
"""
type schedule {
activity: String
end_at: timestamptz
id: Int
"""An array relationship"""
speakers(
"""distinct select on columns"""
distinct_on: [talk_speakers_view_select_column!]
"""limit the number of rows returned"""
limit: Int
"""skip the first n rows. Use only with order_by"""
offset: Int
"""sort the rows by one or more columns"""
order_by: [talk_speakers_view_order_by!]
"""filter the rows returned"""
where: talk_speakers_view_bool_exp
): [talk_speakers_view!]!
start_at: timestamptz
talk_description: String
talk_type: String
title: String
}
I am suspecting that it looks like id: Int is missing ! in the schema, is the cause of codegen interpreting it as optional. But I could be wrong too. Here's the repo for the complete reference https://github.com/vinamelody/MyApolloTest/tree/test
It's because Postgres marks view columns as explicitly nullable, regardless of the underlying column nullability, for some unknown reason.
Vamshi (core Hasura server dev) explains it here in this issue:
https://github.com/hasura/graphql-engine/issues/1965
You don't need that view though -- it's the same as doing a query:
query {
talks(
where: { activity: { _like: "iosconfig21%" } },
order_by: { start_at: "asc" }
}) {
id
title
start
<rest of fields>
}
Except now you have a view you need to manage in your Hasura metadata and create permissions for, like a regular table, on top of the table it's selecting from. My $0.02 anyways.
You can even use a GraphQL alias if you really insist on it being called "schedule" in the JSON response
https://graphql.org/learn/queries/

How do I effectively use CouchDB with normalized data?

It has taken me quite a long (calendar) time to get my head around CouchDB and map/reduce and how I can utilize it for various use cases. One challenge I've put myself to understanding is how to use it for normalized data effectively. Sources all over the internet simply stop with "don't use it for normalized data.". I do not like the lack of analysis on how to use it effectively with normalized data!
Some of the better resources I've found are below:
CouchDB: Single document vs "joining" documents together
http://www.cmlenz.net/archives/2007/10/couchdb-joins
In both cases, the authors do a great job at explaining how to do a "join" when it is necessary to join documents when there is denormalized commonality across them. If, however, I need to join more than two normalized "tables" the view collation tricks leveraged to query just one row of data together do not work. That is, it seems you need some sort of data about all elements in the join to exist in all documents that would participate in the join, and thus, your data is not normalized!
Consider the following simple Q&A example (question/answer/answer comment):
{ id: "Q1", type: "question", question: "How do I...?" }
{ id: "A1", type: "answer", answer: "Simple... You just..." }
{ id: "C1", type: "answer-comment", comment: "Great... But what about...?" }
{ id: "C2", type: "answer-comment", comment: "Great... But what about...?" }
{ id: "QA1", type: "question-answer-relationship", q_id:"Q1", a_id:"A1" }
{ id: "AC1", type: "answer-comment-relationship", a_id:"A1", c_id:"C1" }
{ id: "AC2", type: "answer-comment-relationship", a_id:"A1", c_id:"C2" }
{ id: "Q2", type: "question", question: "What is the fastest...?" }
{ id: "A2", type: "answer", answer: "Do it this way..." }
{ id: "C3", type: "answer-comment", comment: "Works great! Thanks!" }
{ id: "QA2", type: "question-answer-relationship", q_id:"Q2", a_id:"A2" }
{ id: "AC3", type: "answer-comment-relationship", a_id:"A2", c_id:"C3" }
I want to get one question, its answer, and all of its answer's comments, and no other records from the databse with only one query.
With the data set above, at a high level, you'd need to have views for each record type, ask for a particular question with an id in mind, then in another view, use the question id to look up relationships specified by the question-answer-relationship type, then in another view look up the answer by the id obtained by the question-answer-relationship type, and so on and so forth, aggregating the "row" over a series of requests.
Another option might be to create some sort of application that does process above to cache denormalized documents in the desired format that automatically react to the normalized data being updated. This feels awkward and like a reimplementation of something that already exists/should exist.
After all of this background, the ultimate question is: Is there a better way to do this so the database, rather than the application, does the work?
Thanks in advance for anyone sharing their experience!
The document model you have is what I would do if I'm using traditional relational database, since you can perform joins more naturally with those ids.
For a document database however, this will introduce complexity since 'joining' document with MapReduce isn't the same thing.
In the Q&A scenario you presented, I would model it as follow:
{
id: "Q1",
type: "question",
question: "How do I...?"
answers: [
{
answer: "Simple... You just...",
comments: [
{ comment: "Great... But what about...?" },
{ comment: "Great... But what about...?" }
]
},
{
answer: "Do it this way...",
comments: [
{ comment "Works great! Thanks!" },
{ comment "Nope, it doen't work" }
]
}
]
}
This can solve a-lot of issues with read from the db, but it does make your write more complex, for example when adding a new comment to an answer, you will need to
Get the document out from CouchDB.
Loop through the answer and find the correct position, and push comment into the array.
Save document back to CouchDB.
I'd only consider to spit the answer as a separate document if there's a-lot of them (e.g. 1 question yield 1000 answers'), otherwise it's easier to just package them in a single document. But even in that case, try putting the relationship info inside the document, e.g.
{
id: "Q1",
type: "question",
question: "How do I...?"
}
{
id: "A1",
type: "answer",
answer: "Simple... You just..."
question_id: "Q1"
}
{
id: "C1",
type: "comment",
comment: "Works great! Thanks!"
answer_id: "A1"
}
This can make you'r write operation easier but you will need to create view to join the documents so it returns all documents with one request.
And always keep in mind that the return result from a view is not necessary a flat structure like rows like in sql query.

Symfony doctrine versionnable behaviour ignore fields

I have a versionable table in my schema. I want it not to be versioned when i change status for example, but versioned when i change shippingPrice.
MyOrder:
actAs:
Timestampable:
Versionable:
versionColumn: version
className: %CLASS%Version
auditLog: true
columns:
userId: { type: integer, notnull: true }
status: {type: enum, values: ["status1", "status2"]}
shippingPrice: { type: float, notnull: true }
#more columns
How can i do that ?
This article might be of some interest:
http://blog.solutionset.com/wpmu/2009/08/26/doctrine-with-nested-i18n-versionable/
The author wants to nest I18N functionality with Versionable. The problem is slightly different; you can't even build the database when you nest I18N and Versionable, but the solution he came up with might be useful.
In essence, he rolled his own Versionable. Not the most pleasant prospect, but looking at how he implemented it might save you some time on your own spike.
This is a bit hacky but should do what is required I think.
I haven't tested it but my understanding is that if you do a dql update() Versionable is not triggered.
Like this
$result = $this->createQuery()
->update('MyOrder m')
->set('m.status', $var)
->execute();
But if you retrieve the object, change it and save thus:
$m = MyOrderTable::getInstance()->findOneById($id);
$m->setShippingPrice($price);
$m->save();
Then Versionable will be triggered so you should get a new version.
So you could use this to solve the problem.

symfony 1.4 updating some object while (or after) saving another one related to it

I have a doctrine form in Symfony, which saves certain object in a table in the DB.
By doing this, I wish to also update another object, which has a relation to the first one, so the objects get the relation (one-to-many) updated as the first object gets saved.
I really don't know if this is possible at all...
I'll post my code, as a reference:
Schema:
Entry:
columns:
pic: { type: integer, notnull: false, default: null }
relations:
Pic:
local: pic
foreign: id
onDelete: SET NULL
Pics:
type: many
class: Pic
local: id
foreign: entry_id
Pic:
columns:
id: { type: integer, notnull: true, primary: true, autoincrement: true }
entry_id: { type: integer, notnull: true, primary: true }
pic: { type: string(255), notnull: true }
relations:
Entry:
local: entry_id
foreign: id
onDelete: CASCADE
I have another many-to-many relation between Pic and Entry, because an Entry may have a lot of Pics, but the first Pic I create must also be defined as the 'default' Pic which I stablish in the Entry.pic field...
(I previously and correctly create an Entry, so now I must get a new Pic, which will be the 'default' one for the Entry)... In the create actions for the Pic table, I wish to update the Entry so it knows the brand new Pic I have just added and that should get linked by 'default' with it...
Pic actions.class.php:
public function executeCreate(sfWebRequest $request)
{
$this->form = new PicForm();
$this->form->bind(
$request->getParameter($form->getName()),
$request->getFiles($form->getName())
);
if ($form->isValid())
{
$this->pic = $form->save();
$entry = $this->pic->getEntry();
$entry->updateSetPic($this->pic);
$this->redirect('entry_show', $entry);
}
}
Finally, I have the following 'updateSetPic' method in the lib/model/doctrine/Entry.class.php file:
public function updateSetPic(Pic $pic)
{
$this->setPic($pic);
$this->save();
}
The problem I have right now is that, seemingly, the upateSetPic method, receiving the recently saved Pic object (in the Pic actions create method), just receives nothing, as if the Pic object that the $form->save() method has nothing in it (even though, it truly saves, but maybe at this stage it isn't commited or something?)
So my question is, am I doing this all right? Or where am I wrong? Is there a way to acomplish what I need? If so, what is that way? Maybe I need to mingle into another part of the Pic save process, but I'm kind of lost by now...
Any ideas?
Thank you!
In your "$form->isValid()" if statement, it seems your $entrada, that you're calling updateSetPic on, is not set.
But to answer your question, you might want to look at the postSave() function you can add to your object ( http://www.doctrine-project.org/projects/orm/1.2/docs/manual/event-listeners/en ).

Confused between Language & Culture! :(

I'm repeatedly getting confused between Language & Culture in Symfony.
- I'm setting culture as (en_US) which I guess is correct
- but translation files are created for a language (en)
- also, when using translation in the database, the lang=en
I have a model whose definition is as follows:
Option:
package: Options
tableName: Com_Options
actAs:
I18n:
fields: [name, tooltip]
columns:
id:
type: integer(2)
primary: true
notnull: true
unsigned: true
# autoincrement: true
name:
type: string(50)
notnull: true
notblank: true
tooltip:
type: string(100)
sequence:
type: integer(1)
unsigned: true
range: [0,255]
This class is referred by several other classes.
When I try to print the name as $refObj->Option->Name I get nothing. When I check the queries, I see that 3 queries are fired in all.
1) to get refObj
2) to get Option
3) to get Translation
But the real problem is that for 3, there is no language parameter in the query.
I wonder how it will get the translated name? Current value of sf_culture: en_US
Is there another way to access the 'name' according to user's language?
Or do I need to write custom queries on every model?
Is the problem because autoincrement is OFF, or because Im using a package?
Thanks a lot!
Found this: a very tedious & costly method, but works:
$class->relation->Translation[$lang]->property
If you wish to read directly from database
$q = Table::getInstance()->createQuery('a')
->select('a.id, t.name')
->leftJoin('a.Translation t')
->where('t.lang = ?', $lang);
return $q->execute(array(), Doctrine::HYDRATE_NONE);
If you use XLIFF files, you need not pass culture/language
__('text which is translated in the XLIFF for user\'s culture');

Resources