As http://docs.phalconphp.com/en/latest/reference/models.html#understanding-records-to-objects says, you can edit the objects once its loaded in the memory.
$settingCategories = SettingCategory::find();
foreach($settingCategories as $settingCategory){
if($settingCategory->type == "2"){
$settingCategory->type = "asd";
$settingCategory->intersection = "asd";
}else{
$settingCategory->type = "blaa";
$settingCategory->intersection = "blaa";
}
$settingCategory->type = "test";
}
$this->view->setVar("settingCategories",$settingCategories);
type is still its default value when I loop through it with volt:
{% for settingCategory in settingCategories %}
<div class="tab-content">
<h4>{{ settingCategory.name }}</h4>
<h4>{{ settingCategory.type }}</h4> --> still (int) integer!?
<h4>{{ settingCategory.intersection }}</h4> --> undefined!?
</div>
{% endfor %}
When you are modifying a variable inside a foreach, you are modifying a "temporary variable". What it means is that since it is only a copy of the real variable, when you change it, the real value inside the array isn't changed. Now, on to what you could do to solve this:
Setters/Getters
I personally prefer this one. If what you want to do is data transformation (I.E. you change the value of a field from one thing to another, and you want to use the new value in your code everywhere), I would use setters and getters. Here is an example:
// This is inside your model
protected $type;
public function getType()
{
if ($this->type === 2) {
return "asd";
} else {
return $this->type;
}
}
public function setType($type)
{
if ($type === 2) {
$this->type = "asd";
} else {
$this->type = 1; // or $type, or anything really :)
}
}
Of course, in your code, you'll have to change $category->type to $category->getType() and $category->setType($type), based on whether you are reading the value or assigning something to it.
The Quick and Dirty Way
Well, if your use case is different, you can use your current code block with a simple modification. Change your foreach to foreach($settingCategories as &$settingCategory). The ampersand makes the variable be passed into the block as a reference (I.E. it is not a copy like your current case). That means changing it will change the real value.
Related
I have this file that stores some of my environment variables.
Let's call it generalEnv.js
module.exports = {
CONSTANT_1: process.env.CONSTANT_1,
CONSTANT_2: process.env.CONSTANT_2
};
When the app initializes, I don't put the value of process.env.CONSTANT_1 in the env variables yet because I have to look into some places first if it exists(mongodb for instance). If it does not exists on mongodb, I will add a value into process.env.CONSTANT_1 and I was expecting that the value will reflect on generalEnv now.
When I tried accessing the CONSTANT_1 in another file.
Let's call it getConstantOne.js
const { CONSTANT_1 } = require('./generalEnv');
module.exports = () => {
// I was expecting that CONSTANT_1 will have a value here now
if(!CONSTANT_1) {
// do something
}
return CONSTANT_1
}
it does not reflect.. how do I update the closure of generalEnv.js for process.env.CONSTANT_1 to reflect on CONSTANT_1?
When assigning to a variable (or a value in an object/element in an array), the assignment will replace the value, not modify it. Therefore, any "copies" of that value will not be affected, and remain the same. Consider this example:
let a = 0;
let b = a;
a = 1;
What happens to b? Answer: Its value is 0.
To work around this we need some way of modifying the value instead of replacing it. Unfortunately, "primitive types" (strings/numbers/booleans etc.) cannot be modified in javascript. There are types that can be modified however, such as objects. You could solve this by wrapping your variables in an object called "env".
let env: {
CONSTANT_1: process.env.CONSTANT_1,
CONSTANT_2: process.env.CONSTANT_2
}
modules.exports = { env }
and then to modify:
env.CONSTANT_1 = "new value"
and to access:
if (!env.CONSTANT_1) { ... }
I have a simple nested tag:
<nested-tag>
<p>myTitle: {myTitle}</p>
<p>{myKeyword}</p>
this.myTitle = opts.title;
this.myKeyword = opts.keyword;
</nested-tag>
You can see I assign the opts.title and keyword to two new variable myTitle and myKeyword.
Then I use it in a loop of a parent tag:
<my-tag>
<input type="text" onkeyup={search} value={keyword} />
<ul>
<li each={items}>
<nested-tag title={title} keyword={parent.keyword}></nested-tag>
</li>
</ul>
this.keyword = ""
var initItems = [{ title: "aaaa"}, { title: "bbbb"} ]
this.items = initItems
this.search = function(event) {
this.keyword = event.target.value;
this.items = initItems.filter((item) => item.title.indexOf(this.keyword) >=0 );
}
</my-tag>
You can see I passed the parent.keyword to nested-tag as keyword variable.
When I input something to the text input, the keyword will be changed, so the <nested-tag> will be recreated with the new parent.keyword.
But it's not, the {myKeyword} of nested-tag is always empty. I have to rewrite it with directly opts.keyword invocation:
<nested-tag>
<p>opts.title</p>
<p>opts.keyword</p>
</nested-tag>
And it's working well now.
I'm not sure why and how to fix it? Do I have to always use opts.xxx in the nested tags?
A live demo is here:
http://jsfiddle.net/3jsay5dq/10/
you can type something to the text input to see the result
The javascript in your component nested-tag gets run when instantiating the component. So, when the component is getting generated, the myTitle and myKeyword will be initialized with whatever opts are passed in. But, on update, the myTitle and myKeyword are still pointing to the values set during instantiation. The cleanest way to go about it is to use opts[key] as they will always reflect what is being passed to the component. If you insist on using your own local properties, then you could modify your component like this:
<nested-tag>
<p>myTitle: {myTitle}</p>
<p>{myKeyword}</p>
// this will run every time there is an update either internally or from a passed opts
this.on('update', () => {
this.myTitle = this.opts.title;
this.myKeyword = this.opts.keyword;
})
// this will only run once during instantiation
this.myTitle = opts.title;
this.myKeyword = opts.keyword;
/*
// could be refactored to
this.setMyProps = () => {
this.myTitle = this.opts.title;
this.myKeyword = this.opts.keyword;
}
// bind it to update function
this.on('update', this.setMyProps)
// run once for instantiation
this.setMyProps()
*/
</nested-tag>
I see this code for how create a table with closure
https://varomorf.wordpress.com/2014/09/22/update-jtable-using-groovy/
but now I need create a table with closure
but using a text title for create all closure variable
like this; this code get the table but using the last value of xbn in this case 4
theTable = table(){
tableModel(){
var1="fecha"
xbn=0
stx="date;product;quant;weight;price".split(";")
println it
while(xbn<4) {
closureColumn(header:stx[xbn], read:{it[stx[xbn]]}) ;xbn=xbn+1 }
}
}
normally my code without loop
look like this
theTable = table(){
tableModel(){
var1="fecha"
xbn=0
stx="date;product;quant;weight;price".split(";")
println it
closureColumn(header:"date", read:{it["date"]})
closureColumn(header:"product", read:{it["product"]})
closureColumn(header:"quant", read:{it["quant"]})
closureColumn(header:"weight", read:{it["weight"]})
closureColumn(header:"price", read:{it["price"]})
}
}
please help me
Most DSLs don't prevent you from using the regular groovy stuff. So you can iterate multipl times, but you have to name your closure loop vars (e.g. your outer loop is the tableModel and it's implicitly named it).
...
tableModel() { // it ->
...
"date;product;quant;weight;price".split(";").each { hdr -> // name the loop var
closureColumn(header:hdr, read:{it[hdr]})
}
...
}
...
For a project I'm using pommbundle, it's perfect for generating entities with an existing database.
In my controller:
$catalogues = $this->get('pomm')['my_db1']
->getModel('\AppBundle\Entity\MyDb1\PublicSchema\CatalogueModel')
->findAll();
return this->render(
'SiteBundle:Default:homePage.html.twig',
array('catalogues'=>$catalogues));
But how can I access the variable inside my view (Twig)
{% for catalogue in catalogues %}
{{dump(catalogue)}} --> value inside
{% endfor %}
Result dump
Catalogue {#1132 ▼
#container: array:13 [▼
"ID" => 8
"Code" => "MATIÈRE PREMIÈRE"
"Actif" => true
"DateAjout" => DateTime {#1212 ▶}
"Index" => 0
"PriseCommande" => false
"Description" => ""
"Couleur" => "Green"
"CouleurText" => "#000000"
"Tarif" => null
"WebActif" => false
"WebTitre" => null
"WebDescription" => null ]
-status: 1 }
catalogue.ID (not working) catalogue.container.ID (not working)
with catalogue.get('ID') works but it's the best way?
Other question
If my entity has a relation, e.g. WebActif -> relation with another table,
How to access Webactif because the dump returns only an ID.Do I have to create my own method?
Is it possible to show a basic example?
The Model::findAll method returns an iterator on database results. When this iterator is traversed, it returns entities filled with converted values.
Note: you’d better not use upper case letters in your column names as it will lead to confusion and it will not work properly with Pomm flexible entities. (same applies for table names).
<dl>
{% if catalogues.isEmpty() %}
<dt>No results found.</dt>
{% else %}
<dt>There are {{ catalogues.count() }} results:</dt>
{% for catalogue in catalogues %}
<dd>{{ catalogue.code }} (added the {{ catalogue.date_ajout.format('d-m-Y') }}){% if catalogue.actif %} OK {% endif %}</dd>
{% endfor %}
{% endif %}
</dl>
Edit: Since your comment says your database contains capitalized column names here is an additional explanation on how flexible entities work.
(Official documentation about flexible entities is here)
When a flexible entity is hydrated by the iterator values, they are converted and then pushed with their name in the entity. This is why you can use the generic accessor $entity->get('MyColumn') because keys are preserved.
But flexible entities are strange beasts because they can change depending on the SELECT that decides the data sent to them. When such entity is created the getters and setters are virtually created using PHP’s __get and __set and __call functions.
This can seem weird but look at this example:
<?php
$entity = new MyEntity(['first_name' = 'John', 'last_name' => 'Doe']);
$entity['first_name']; // calls $entity->getFirstName() which defaults to $this->get('first_name');
It is then possible to override default accessors:
<?php
class MyEntity extends FlexibleEntity
{
/*
* Triggered by $entity['first_name']
* or $entity->first_name
*/
public function getFirstName(): string
{
return uc_words($this->get('first_name'));
}
public function getLastName(): string
{
return strtoupper($this->get('last_name'));
}
public function getName(): string
{
return sprintf("%s %s", $this->getFirstName(), $this->getLastName());
}
}
Then, in twig it is possible to simply do {{ entity.name }} to trigger the getName function.
As you can see, the column names are camel cased to create the virtual accessors, this operation can be reversed only if the original column names are in lower case.
I have created a custom function I can access from the volt. The function seems to work fine, but I cannot manage to send the variable to the function. It sends the variable as text instead of its value.
The twig function:
$volt->getCompiler()->addFunction('getusergroup', function ($user) {
return \Models\User::getUserGroup($user);
});
The function in the Model:
public static function getUserGroup($user) {
return UserGroup::find(array('conditions' => 'user_id = ' . $user));
}
The lines in Twig to call the function:
{% for member in getusergroup(staff.id) %}
{{ member.Group.name }}
{% endfor %}
The error I get:
'Scanning error before 'staff->id' when parsing: SELECT
[Models\UserGroup].* FROM [Models\UserGroup] WHERE user_id =
$staff->id (78)' (length=131)
As you can see, in stead of $staff->id being an integer, it's the text.
How do I go about sending the actual ID to the function?
By the way, I am using twig in combination with Phalcon and followed the instructions in this article: http://phalcontip.com/discussion/60/extending-volt-functions
If you dump $user inside of your method public static function getUserGroup($user), you will receive this $staff->id, but you actually want something like 42.
To avoid this register the Volt function like this:
$volt->getCompiler()->addFunction('getusergroup', function ($resolvedArgs, $exprArgs) {
return 'Models\User::getUserGroup(' . $resolvedArgs . ')';
});
More info on Extending Volt Functions