I have a MySQL database (that is later imported into Doctrine) set up that links 3 different tables by way of foreign keys. The relationship is as follows: Many As go to one B, and many Bs go to one C. For the web page that I am trying to create, I need some of the related B's information on a page about A, while being categorized by C.
Think of it like this: A is "dog_food", B is "company", and C is "company_category". That is, on a page displaying different kinds of dog food, I need to display information about the manufacturing company; I only display those dog foods based on how the user specifies what kind of company they want to buy from.
Pulling information dynamically from A is trivial, since the repository is pulled and the rows exist as entities. Say, {{ dog_food.price }} would call (if specified in a for loop, this is Twig code) a single instance's price.
I have read about the #OneToOne, #OneToMany, etc. annotations, but have not been able to find a way to easily utilize their effects inside of a Twig template. The aggregate entities and repositories for all 3 tables exist as variables in the Controller. It should be mentioned that, continuing with this example, that there is a single companyID field in table B corresponding to multiple dog foods, and a single categoryID associated with multiple companies.
What happens if I want to list the company name above the price? How do I access that information in Doctrine, and furthermore, in Twig?
I will translate what you've said above into code that I would effectively write if I was you:
So, I assume that, along with the mapping you defined , your company category entity is called 'Company_category', your dog food entity is called 'Dog_food'.
I would pass the id of the company_category to an action in my controller,
then, I would retrieve all the companies that belong to that company_category, something like this:
public function xyzAction($id){
$companies=$this->getDoctrine()->getRepository('XYZYourBundle:Company')
->findBy(array('company_category'=>$id));
//Hold on I will just complete it
}
Then I would retrieve all the dog foods objects from my DB, that the company's exist in $companies, the result returned in the first line of code,
to do this, I would first:
1-Define my own criteria:
this would help you define a complex , powerful conditions and it's easy to use.
2-Use my criteria to filter the result of the repository, this would be useful
So let's update our action:
public function xyzAction($id){
$companies=$this->getDoctrine()->getRepository('XYZYourBundle:Company')->findBy(array('company_category'=>$id));
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where($criteria->expr()->in('company',$companies));
$dogfoods=$this->getDoctrine()->getRepository('XYZYourBundle:Dog_food')->matching($criteria)
//Hold on I will just complete it
}
and finally render our dogfood objects to a twig template:
public function xyzAction($id){
$companies=$this->getDoctrine()->getRepository('XYZYourBundle:Company')->findBy(array('company_category'=>$id));
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where($criteria->expr()->in('company',$companies));
$dogfoods=$this->getDoctrine()->getRepository('XYZYourBundle:Dog_food')->matching($criteria)
return $this->render('XYZYourBundle:test.html.twig', array(
'dogfoods'=>$dogfoods));
}
Now, let's place ouselves in a twig template, we're gonna iterate through our $dogfoods objects and we will display some information, assuming you defined the needed getters and setters;
{% for dogfood in dogfoods %}
{{dogfood.price}}
{{dogfood.company}}
{% endfor %}
Edit :
you can get the company's name by either:
-implement a tostring method that returns the company's name and in twig use
{{dogfood.company}}
or
-in twig, use
{{dogfood.company.name}}
Hope this helps you, if something doesn't work just tell me.
Related
I'm very much a beginner when it comes to database relationships hence what I suspect is a basic question! I have two database tables as follows:
Projects
id
company_id
name
etc...
rfis
id
project_id (foreign key is id on the Projects table above)
Number (this is the column I need help with - more below)
question
The relationships at the Model level for these tables are as follows:
Project
public function rfi()
{
return $this->hasMany('App\Rfi');
}
RFI
public function project()
{
return $this->belongsTo('App\Project');
}
What I'm trying to achieve
In the RFI table I need a system generated number or essentially a count of RFI's. Where I'm finding the difficulty is that I need the RFI number/count to start again for each project. To clarify, please see the RFI table below which I have manually created with the the 'number' how I would like it displayed (notice it resets for each new project and the count starts from there).
Any assistance would be much appreciated!
Todd
So the number field depends on the number of project_id in the RFI table. It is exactly the number of rows with project_id plus one.
So when you want to insert a new row, you calculate number based on project_id and assign it.
RFI::create([
'project_id' => $project_id,
'number' => RFI::where('project_id', $project_id)->count() + 1,
...
]);
What I understood is that you want to set the value of the "number" field to "1" if it's a new project and "increment" if it's an existing project. And you want to automate this without checking for it every time you save a new row for "RFI" table.
What you need is a mutator. It's basically a method that you will write inside the desired Model class and there you will write your own logic for saving data. Laravel will run that function automatically every time you save something. Here you will learn more about mutators.
Use this method inside the "RFI" model class.
public function setNumberAttribute($value)
{
if(this is new project)
$this->attributes['number'] = 1;
else
$this->attributes['number']++;
}
Bonus topic: while talking about mutators, there's also another type of method called accessor. It does the same thing as mutators do, but just the opposite. Mutators get called while saving data, accessors get called while fetching data.
I have a question about how to access fields from pre-existing pages and display them in a different page.
For example I have a document type called: "People" and I create a page for several people so that the structure of my content section looks like this:
Home
page1
page2
page3
People
person1
person2
person3
The document type "People" uses contains the fields:
Name, Age, Job, Description all as textboxes.
What would you suggest is the best way of accessing the values in these fields for each page so that you loop through each person under the parent "People" and display their name/age/desc?
Using:
#{
var selection = Umbraco.TypedContent(1108).Children()
.Where(x => x.IsVisible());
}
#foreach(var item in selection){
}
I can only access the metadata for each page such as #item.Id but I cant work out how to access the fields so say #item.Name returns the persons name.
Any help will be really appreciated! Cheers.
What you get from the query above is instances of your content as IPublishedContent. This is a pretty generic interface for any type of published content, so you will not be able to directly access the specific custom properties you have defined on your document types, as normal C# properties on this object.
However - if you have ModelsBuilder enabled in your site, you should be able to do the following and get the children returned as mapped POCO classes:
var selection = Umbraco.TypedContent(1108).Children<Person>()
(or <People> .. depending on what the actual document type alias of the child items is called)
If you are not using ModelsBuilder, you would have the option of just doing this inside your foreach loop to get the values of your properties instead:
var age = item.GetPropertyValue<string>("age");
Bonus note: please rename your Name property to something else (fullname or something like that). Using Name will clash with the built-in property used for the node name :)
I'm trying to output the filter results with only matching elements.
I have two tables (in the real project, which will be 5), let's say companies and projects. A company may have more than one project or may not have any.
These are the relations:
/app/models/Company.php
<?php
class Company extends Eloquent {
public function projects() {
return $this->hasMany('Project','companyID');
}
protected $table = 'companies';
}
/app/models/Project.php
<?php
class Project extends Eloquent {
public function companies() {
return $this->belongsTo('Company','companyID');
}
}
What I want to do is, I want to get results of them both but only with matching parameters.
I've tried this:
return Company::with(array('projects'=>function($query){
$query->where('id',99); //project's id is 99
}))->get();
This is the output JSON
If I change the value from 99 to 1 (there is a result with products.id of 1), it changes into this:
I only want to get the second result from the second JSON i've posted.
As you can see in the second JSON (I'm using this parser to check), all companies are loaded regardless of the project, and only the rows matched have the object projects.
There will be more 'with's and I don't know how to filter only matching elements.
I also tried having() inside closure, but it's still same:
$query->having('projects.id','=',99);
Is there a way to filter only matching results (without using a loop) which the output will only include the results having the matched projects object?
Edit: Actually, 5 tables will be filtered.
companies, projects, works, users and user_works
Let's say;
"Companies" have many projects.
"Projects" have many works
"Works" have many users, also "Users" may have more than one work (pivot table user_works).
All relations are set correctly from models.
I want to do a global searching to these.
Something like: "Bring me the user id 1's works which has company id of 5 and project id of 4", but none of the fields are mandatory.
So these are also valid for searching: "Bring me everyone's works on project id of 2", or "bring me id 2's works", or "bring me all the works starting from today", "bring me the id 1's works on project 2", "Bring me this year's works done of company id 1".
Thanks in advance
Using whereHas() is the solution on my case. It filters relation and affects the results returned in the main query.
If you have the id of the project, would it make more sense to go that route? $project = Project::find(99); and then the company variables would be accessible with $project->companies->name;
It would make more sense to rename the companies() function to company() because a project will only ever belong to one.
I am attempting to access values in the Categories and Keywords information for a Tridion Publication via a Razor TBB in Tridion 2011. The Razor documentation lists the following example code:
<ul>
#foreach (var keyword in Publication.MetaData.SomeKeywordFields) {
<li>#keyword.Title (#keyword.Id)</li>
}
</ul>
I have a Keyword inside of a Category though... in fact, that's the only way I am myself aware that you can even have a Keyword in Tridion, but correct me if I am wrong. Extrapolating from the example's syntax, I tried the following where "myCategory" is a Category in the publication, and "myKeyword" is a Keyword inside of the myCategory Category:
#foreach (var keyword in Publication.MetaData.myCategory) {
if(#keyword.Title == "myKeyword") {
#keyword.Title
}
When I run this template, I get an error stating that DynamicItemsFields: Key 'testcategory' Not Found In ItemFields (Object reference not set to an instance of an object)
Can anyone help with identifying if it is even possible to do what I am attempting here (as it seems like it is based on the documentation but still not sure) and if so, provide an example of the correct syntax?
You're almost there with your code except that you're using the actual CategoryName. As Puf commented, you have to use the "fieldname" of you Publication Metadata not the actual CategoryName. You should just change the "myCategory" to the actual fieldname
#foreach (var keyword in Publication.MetaData.*<<FIELDNAME>>*) {
if(#keyword.Title == "myKeyword") {
#keyword.Title
}
}
[FIELDNAME] --> is the XMLName of publication metadata schema.
Keywords are indeed always within a Category or another Keyword. But they are used within items like Components and (as in the example) metadata on Publications, Folders, etc.
The example from the documentation is outputting each value of a multi-valued metadata Keyword field on the Publication (i.e. "Allow Multiple Values", "Values selected from a list" and "Category" all checked in the Metadata Schema).
If you are trying to do something similar, you can indeed modify the name of the field and it will work. From your question, however, it seems like you are trying to loop over all Keywords within a certain Category - which requires a different approach.
For that, you would need the equivalent of a GetList call within your TBB. I'm not familiar enough with the Razor mediator to provide sample code for that, sorry.
Thanks to Ram G in chat:
The Publication itself, typically your 010, 020... 050 etc. levels, can have a metadata schema attached to them as well. The XMLName of the field being targeted by the Razor logic block above is actually the field name of this metadata schema item, not the name of the Category itself. In the metadata schema for the publication, if you select the Design tab, Make your XML field for the item a "Text" type, select "Options will be selected from a list", by default, another Checkbox will appear called "Category" which, if checked, automatically pulls in the full list of Category items present in that publication. So, when that Field is targeted by the Razor logic now, it is in multiple steps targeting the Category value as well.
Thanks again Ram G
I've got records in my MySQL projects database that have several boolean flags to help me sort the data. I have 3 categories planning, landscape, and environmental and 4 classes (or subcategories) for each category; industrial, government, education, residential.
My goal is to use ColdFusion to create and store the project_id numbers in an array of some kind that will basically have the projects sorted by category and class. That way I can grab just the industrial projects in the planning category and construct a link to that project.
So, the first position in the array would be planning and inside that first position would be the 4 classes, then, within that would be all of the project_id numbers that returned true for those particular criteria.
The logic I'm looking to create goes like this...
Loop over the query result, if planning = true and industrial = true, place the project id # into the planning array inside the industrial array.
How can I use <cfloop> to loop over the list of project records, recognize the category and class flags and construct a clean and usable dataset? Can this be handles in the query in some way?
Figure out the desired data structure
look at your existing data structure
figure out the algorithm to translate from one to the other
You may cfloop the query, and use a large cfswitch (or large set of if-then-else) to figure out how you want to store the id in your desired data structure. Or if you can map the class/category name as a struct key, then it might be easier.
Or you may use cfoutput group="" if it helps (cfloop group="" is available on in CF10+)
Finally, maybe you don't even need the data structure, just use Query of Queries wherever you need.
You may be able to utilize the Underscore.cfc library for this. For example, you could use the filter function to extract an array of structs representing the query rows you want:
planningArray = _.filter(queryResult, function(row){
return (row.planning == true && row.industrial == true);
});