how can partialLoop viewhelper be used in zend3 with tablegateway - zend-db

I still have trouble to get used to Zend3 framework. Before I have used Zend 1, it might be still an understanding problem due to tablegatewayadapter. I just want to show 2 entities together, which would be projects 1-n units.So I have to pass the projectkey somehow to my unitarray to get only the related units. In Zend1 I realised this (in another example) with a partialloop helper which shows the n entity, here are the relations "veranstaltung - docs", same idea, other tables.
This is a snippet, that shows what I former did in zend1:
$veran=new Application_Model_DbTable_Ribaveranstaltungen();
$documents = new Application_Model_DbTable_Ribadocs();
$select=$veran->select()
->from('riba_veranstaltung')
->order('sort DESC');
$veranstaltung=$veran->fetchAll($select);
foreach($veranstaltung as $v) :
$dokument=$documents->getDocumentveranstaltung1($v->id);?>
<tr>
<td> <a href="<?php echo $this->url(array('controller'=>'Ribaveranstaltungen',
'action'=>'index'));?>"><img src="./images/icons/haus.jpg" width="20" height="20" /></a></td>
<td class="row_0"><?php echo $v->veranstaltung;?></td>
<td class="row_1"><?php echo $this->partialLoop('/helpers/_docs-row.phtml', $dokument);?></td>
</tr>
<?php
$j=$j+1;
endforeach;?>
How to migrate this to zend3. I had several ideas, for example
1.idea: I tried within with my controller:
public function indexAction()
{
//'imports' => $this->table->fetchAll(),
return new ViewModel([
'projects' => $this->projectTable->fetchAll(),
'units' => $this->unitTable->fetchAll(),
]);
}
Here is my trouble, how to use my method fetchALLP(project), because I want to pass the actual projectkey to the units to get only the related records.
2.idea: I tried to do just the same, as I did in Zend1. I wanted to initite my object in my view.
$gateway = new Unit();
$units = new UnitTable($gateway);
foreach ($projects as $project) :
$unit=$units->fetchAllP($project->ProjectID);?>
This, I just expected it, doesn't work, because I really didn't understand this tableadapter concept. Can somebody please explain it to me close to my example?
The next interesting topic would be, is there still a partialloop helper or do I have to use a new concept also in this case?
EDIT: to show the newest version
I changed my Controller/index action as suggested, it looks now:
$result = $this->unitTable->fetchAll();
$units = $result->toArray();
return new ViewModel([
'projects' => $this->projectTable->fetchAll(),
'units' => $units,
]);
my index phtml (snippet):
foreach ($projects as $project) :
?>
<tr>
<td><?= $this->escapeHtml($project->Projectname) ?></td>
<td><?= $this->escapeHtml($project->PShortcut) ?></td>
<td><?= $this->escapeHtml($project->PCI_Number) ?></td>
<td><?= $this->escapeHtml($project->PDescription) ?></td>
<td><?= $this->escapeHtml($project->PComponent_Class) ?></td>
<?php $this->partialLoop('import/unit/index.phtml', $units);
endforeach; ?>
My partial (snippet of course there is and end of for)
<?php
foreach ($units as $unit) :
var_dump(get_object_vars($units));
?>
<tr>
<td><?= $this->escapeHtml($this->Unitname) ?></td>
EDIT: New experiences
I implemented now like this, the other suggestions didn't show the partial at all:
$this->partialLoop()->setObjectKey('ProjectID');
echo $this->partialLoop('import/unit/unitpartial.phtml', $units);
I get this result:
It shows the first project and afterwards all units. It repeats the units with the number of projects, but doesn't show any other project.
I'm a bit further in any case. I need additional inforation to how can I link the partial to the actual project, I need in the view for example:
project1
Unit x
Unit y
project2
Unit abc
...

In the partialLoop view helper you can pass data or variable as an associative array or an object that implements toArray() method or an object that has an implementation of get_object_vars() for getting its public properties.
public function testAction()
{
$result = $this->unitTable->fetchAll();
$units = $result->toArray();
return new ViewModel([
'projects' => $this->projectTable->fetchAll(),
'units' => $units,
]);
}
First, we would see an example passing an array of data.
We would use $units variable, in this case, because it is an array of data as we converted it to an array.
echo $this->partialLoop('/path/to/partial.phtml', $units);
Now you can output table column name as a variable in your partial template, for example, in /path/to/partial.phtml.
echo $column_name;
// or
echo $this->column_name;
Now, we would see an example passing an object as data.
Guessing $projects variable has not converted into an array, it is an object. You may want to have it passed as an object to the partial script. You can do this by setting the objectKey property like the following
$this->partialLoop()->setObjectKey('project');
echo $this->partialLoop('/path/to/partial.phtml', $projects);
Now in your partial /path/to/partial.phtml template, output object properties like the following
echo $this->project->property_name;

Related

Laravel 8 - Show database results using for loop (not foreach)

Using Laravel 8: I need to display my data (images saved as image names in the db) in 8 columns on the blade page. So if I have a db row count of 18, I would equally distribute the 18 in 8 columns (+remainder if any but that is irrelevant to this q - so, 18 images/8 cols = 2 (+2 remainder)). I can do this using two for loops so:
#for ($col=1; $col<=8; $col++)
#for ($img=1; $img<=$image_percolumn; $img++)
<img src="images/{{$featuredbrands->brandLogo'}}">
#endfor
#endfor
$featuredbrands is being passed from the controller as an array:
class HomeController extends Controller{
public function index(){
$fbrands = brands::join('subscriptions', 'brands.id','=','subscriptions.brandID')
->where('subscriptions.packageID','=',2)
->get(['brands.id','brands.brandLogo','brands.logoLink']);
return view('home',[
'featuredbrands'=>$fbrands
]);
} // end function
} // end class
I am getting the following error for the <img src...> line in my blade page:
Property [brandLogo] does not exist on this collection instance.
To test if I'm passing the data correctly to the blade page, I have tried using foreach to display the images. With foreach, I get the output in one column (so I know that data passed from controller is not the issue).
What is the correct way to reference the image field using the for loop? If that indeed is the problem?
This seems to be much harder than it should be, I am sure I am missing something.
One option - convert your collection to an array, and simply reference elements by key. Something like this:
In your Controller method:
return view('home', [
'featuredbrands' => $fbrands->toArray()
]);
And in your view:
#for ($col = 0; $col <= 16; $col += 2)
<img src="images/{{ $featuredbrands[$col]->brandLogo }}">
<img src="images/{{ $featuredbrands[$col+1]->brandLogo }}">
#endfor
You could also try to do it more the Laravel way, by using the Collection chunk() method, though this also seems very clunky here. Maybe something like:
#foreach ($featuredbrands->chunk(8) as $row)
#foreach ($row->chunk(2) as $col)
#foreach ($col as $brand)
<img src="images/{{ $brand->brandLogo }}">
#endforeach
#endforeach
#endforeach

Showing a specific attribute when generating CRUD in Yii web framwork using giix extenstion

I am generating Models and CRUD for my database tables using giix in YII web framework, the thing is I want to change some of the attributes that showed to me but I dont know how ? I get into the code _FORM.php of the generated CRUD to one of the table and I knew the piece of code that I must change it to get a different attribute instead of one that shown to me without knowing why ?
<div class="row">
<?php echo $form->labelEx($model,'idEmployee'); ?>
<?php echo $form->dropDownList($model, 'idEmployee', GxHtml::listDataEx(Employee::model()->findAllAttributes(null, true))); ?>
<?php echo $form->error($model,'idEmployee'); ?>
</div><!-- row -->
in the previous code the form showed a drop-down list from another table jointed with the current table according to idEmployee, he's showing an attribute that I dont want, I want to know how to render the FirstName and the LastName in the drop-down list, any help please ?
I believe it is easier when you just create your own dropdown list provider
in the Employee.php you add these two functions:
public function getFullName()
{
return $this->first_name.' '.$this->last_name; // or what ever you want to be shown on the drop list
}
public static function getNamesList() {
return CHtml::listData(self::model()->findAll(), 'idEmployee', 'fullName');
}
in the _FORM.php write:
<div class="row">
<?php echo $form->labelEx($model,'idEmployee'); ?>
<?php echo $form->dropDownList($model, 'idEmployee', Employee::getNamesList()); ?>
<?php echo $form->error($model,'idEmployee'); ?>
</div><!-- row -->

Yii: How to populate a Select input with another model data?

I'm playing around with a small app in order to learn to use Yii.
I've created a small webapp with 2 models / tables: Projects and tasks. (1-to-many relationship, properly configured in the model classes).
I'm now trying to customize the Task/create view, replacing the text input field with a select box proposing the list of available projects.
I opened the form view and tried this:
<div class="row">
<?php echo $form->labelEx($model,'project_id'); ?>
<?php echo $form->textField($model,'project_id'); ?>
<?php
// my hack starts here
$projects = Project::model()->findAll();
$list = CHtml::listData($projects, 'id', 'name');
echo $form->listBox($model,'project_id','', $list); ?>
// my hack ends here
<?php echo $form->error($model,'project_id'); ?>
</div>
But it keeps throwing warnings or error (such as Invalid argument supplied for foreach(), and definitely does not work. I'm failing to understand what i'm doing wrong. Can you help ?
Your arguments are not in order (it should be):
$frameworks = Framework::model()->findAll();
$list = CHtml::listData($frameworks, 'id', 'name');
echo $form->listBox($model,'framework_id', $list,array());
Check the documentation
OK, i found it, thanks to Larry Ullman excellent tutorial.
Here it is:
<?php echo $form->dropDownList($model,'project_id', CHtml::listData(Project::model()->findAll(), 'id', 'name')); ?>

Yii CGridView change the header's tr class

So i am working in an app that uses de CGridView extensively but I am porting a webapp from a proprietary framework to Yii. So the CSS files are already written and have been working up until now.
The thing is that in my CGridView widget the headers of columns are enclosed in a TR tag and I have got no clue on where I can add a class attribute to this tag. I've read the documentation and now how to change each header cell individually but not the whole TR.
Thanks for your help!
Ran into a similar problem however as our CSS is for a legacy system I didn't want to roll in yet more CSS rules. In addition I needed support for extra things such as targeting the header with a specific CSS class on the table row and putting in first/last css classes on the items.
To achieve a first/last css on the items you do not need to extend the GridView and can use the handy rowCssClassExpression parameter.
To achieve my second objective of injecting a CSS class into the 'table thead tr' element I did have to override the renderTableHeader() method.
I strongly advise you only consider this route as a last resort because if you update the version of Yii it is conceivable that they make changes that are not backwards compatible with the renderTableHeader() method. Alternatively you could write a test case that runs your widget through a DOM checker to confirm that you only have 1 table element, 1 thead element, 1 tbody element etc...
Yii::import('zii.widgets.grid.CGridView');
class FXSGridView extends CGridView {
public $headerCssClass = 'columnHeadings';
public $itemsCssClass = 'grey';
public $rowCssClassExpression = '$this->rowCssClassFunction($row, $data);';
public $rowCssClass = array('odd','even');
public function rowCssClassFunction($row, $data) {
$classes = array();
if ($row == 0) $classes []= 'first';
if ($row == $this->dataProvider->getItemCount() - 1) $classes []= 'last';
// Do flip/flop on defined rowCssClass
if(is_array($this->rowCssClass) && !empty($this->rowCssClass)) $classes []= $this->rowCssClass[$row % count($this->rowCssClass)];
return empty($classes) ? false : implode(' ', $classes);
}
public function renderTableHeader()
{
if(!$this->hideHeader)
{
echo "<thead>\n";
if($this->filterPosition===self::FILTER_POS_HEADER)
$this->renderFilter();
echo '<tr class="' . $this->headerCssClass . ' ">' . "\n";
foreach($this->columns as $column)
$column->renderHeaderCell();
echo "</tr>\n";
if($this->filterPosition===self::FILTER_POS_BODY)
$this->renderFilter();
echo "</thead>\n";
}
else if($this->filter!==null && ($this->filterPosition===self::FILTER_POS_HEADER || $this->filterPosition===self::FILTER_POS_BODY))
{
echo "<thead>\n";
$this->renderFilter();
echo "</thead>\n";
}
}
}
'columns'=>array(
array(
'name'=>'id',
'header'=>'#',
'htmlOptions'=>array('style'=>'width: 50px; text-align: center;', 'class'=>'zzz'),
'headerHtmlOptions'=>array('class'=>'mytheadclass'),
),
The "headerHtmlOptions" is the one that gives a class to the thead cell of this column.
Unfortunately you cannot do this directly, as there is no provision for adding attributes to the header row tags (see source code).
A straightforward solution would be to subclass CGridView as e.g. MyGridView and override the renderTableHeader method to do what you need it to (add some class variables to MyGridView to let it be configurable). I have used this approach many times in similar situations.
If it's just simple changes you need to make, you might be able to use the generated CSS with something like:
table.admins th {border-right:none;text-align:center;}
table.admins th:first-child {text-align:left;}
etc...
or you could use the Yii-generated ids (view the generated HTML):
<th id="admins-grid_c1">
which may or may not be appropriate depending on how many grids you want to apply the css to and your own naming conventions. You could also use JavaScript/jQuery to manipulate the styles but certainly #Jon's suggestion of creating a custom renderTableHeader is going to give you the most control. (I've also used that approach with lists and renderSorter.)

Saving a checkbox value in Yii

I can't figure out how to properly save checkbox values in Yii. I have a MySQL column, active, defined as a tinyint. I have the following form creation code, which correctly shows the checkbox as checked if the value is 1 and unchecked if 0:
<?php echo $form->labelEx($model,'active'); ?>
<?php echo $form->checkBox($model,'active'); ?>
<?php echo $form->error($model,'active'); ?>
And the code to save the form correctly changes other, text-based values:
public function actionUpdate($id)
{
$model=$this->loadModel($id);
if(isset($_POST['Thing']))
{
$model->attributes=$_POST['Thing'];
if($model->save())
$this->redirect(array('thing/index'));
}
$this->render('update',array(
'model'=>$model,
));
}
The value of active is not saved. Where am I going wrong?
You can use htmlOptions array to specify value attribute. Below is the code example:
<?php echo $form->labelEx($model,'active'); ?>
<?php echo $form->checkBox($model,'active', array('value'=>1, 'uncheckValue'=>0)); ?>
<?php echo $form->error($model,'active'); ?>
Since version 1.0.2, a special option named 'uncheckValue' is
available that can be used to specify the value returned when the
checkbox is not checked. By default, this value is '0'.
(This text is taken from YII Documenration)
For every input that you are accepting from user, you need to define it in model::rule(). is active defined there in rule()?
In general, if you are having problems saving to the database, i would replace
$model->save();
with
if($model->save() == false) var_dump($model->errors);
that way, you can see exactly why it did not save. it is usually a validation error.
Please follow:
1. in protected/models/Thing.php add active as a numeric
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('active', 'numerical', 'integerOnly'=>true),
//OR optional
array('active', 'safe'),
);
}
Controller action: Its ok
View:
<?php echo $form->labelEx($model,'active'); ?>
<?php echo $form->checkBox($model,'active', array('value'=>1, 'uncheckValue'=>0)); ?>
<?php echo $form->error($model,'active'); ?>
Hope this will work for you...
Article which can be helpful when figuring out how to handle booleans & checkboxes in Yii
http://www.larryullman.com/2010/07/25/handling-checkboxes-in-yii-with-non-boolean-values/
I used a bit type field in my DB and it didn't work.
1.- I changed the field type to tinyint
2.- In the rules function added:
array('active','numerical'),
3.-In the form (as D3K said) do:
<?echo $form->checkBox($model,'active',array('value'=>1, 'uncheckValue'=>0));?>
You can check by printing all the attributes which are being captured. If active is not captured, it must not be safe. you need to declare the variable as safe or define a rule around that variable. This will make the variable safe.
I have similar the same problemce before,I change data type is int,so it save
We can also add a rule as safe in model to pass the values from form to controller without missing.
array('active', 'safe'),
well this post is so old but I've found a solution very useful specially for giving checkbox a value specified rather than number. The new syntax is something like this
notice I'm using ActiveForm
field($model3, 'External_Catering')->checkbox(['id' => 'remember-me-ver', 'custom' => true,'value'=>"External_Catering", 'uncheckValue'=>"vide"]) ?>
1) where my model is =>model3
2) with the name External_Catering
3) that take the value External_Catering and empty when it's uncheckValue
4) in Controller you get the value just by specifying the model and it's attribute like
  $External_Catering=$model3->External_Catering.