working with multiple tables data yii2 - yii2

I am new with yii2 and I am having issues printing data from 2 different tables.
//at the end of the model
public function getTeam()
{
return $this->hasOne(Team::className(), ['id' => 'team_id']);
}
// in the controller
public function actionPlay() // IRA no consigo que rule la relacion entre piloto y equipo
{
$player = Player::find()
->leftJoin('team', 'id=team_id')
->orderBy('player_id')
->all();
return $this->render('play', [ 'player' => $player ])
}
Calling the view
<?= $this->render('card/play-steps', ['player'=>$player]) ?>
HTML / PHP
<span><?= $player->player_name ?></span>
<span><?= $player->team_name ?></span>
Seems like I dont understand the way yii2 works with table connections...
what am i missing?
thanks

Related

Add new value to dropdown list

In a projects/create active form I have a field "related company account" as a dropdown (select2 by kartik). Behind this field I'd like to place a plus sign or something else to add new accounts to the dropdown with the following behavior:
gather all input done so far (like $input = compact(array_keys(get_defined_vars())); but probably needed on client side)
jump to accounts/create and pass $input
after submiting the new account jump back to projects/create (e.g. return $this->redirect(Yii::$app->request->referrer);) and fill the previously entered data (extract($input, EXTR_PREFIX_SAME, "arr");)
I'm struggling now with several issues:
Is this process according to best practice or should I change something fundamentally?
How is the button like? Submit button, link or some form of javascript?
Problem with Submit button is that not all required fields may be filled. So saving and resuming/updating the project model might not be possible.
Problem with link is that it is constructed before data was entered
Problem with javascript is that I have no glue
Any hints are welcome. Thank you in advance.
One alternative i would suggest is using Session.
As for the "Add Accounts" button, i would use Submit button, and give different name to actual Submit button (two submit button in form, as answered in here). So, the projects/create view will look like this :
<?php $form = ActiveForm::begin(); ?>
...
...
...
<?= $form->field($model, 'account_id')->widget(Select2::classname(), [
'data' => ArrayHelper::map(Account::find()->all(), "id", "name"),
'options' => ['placeholder' => 'Select a related company account ...'],
'pluginOptions' => [
'allowClear' => true
],
]) ?>
<?= Html::submitButton('Add Account ;)', ['class' => 'btn btn-success', 'name' => 'add_account_submit']) ?>
...
...
...
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
And then check in ProjectsController, which submit button pressed by user. If add account was pressed, then save the inputed field (i would put this function in model for clearance), else, save the model or anything. And, before all that, check if session about project is set, if yes then pre-load it to model (again, in model). Okay, like they say, one code is worth a thousand words, so, this is ProjectsController will look like :
class ProjectsController extends Controller
{
...
...
...
public function actionCreate($category)
{
$model = new Projects();
if (Projects::isSavedInSession()) {
$model->loadFromSession();
}
if (Yii::$app->request->post('add_account_submit')) { // if add_account_submit is clicked
$model->saveTosession(Yii::$app->request->post('Projects')); // I assume your model named Projects, if not, change this value to your model name
return $this->redirect(['accounts/create']);
}
if ($model->load(Yii::$app->request->post()) && $model->save()) {
$model->clearSession(); // we dont need the session anymore
return $this->redirect(['index');
}
return $this->render('create', [
'model' => $model,
]);
}
...
...
...
}
And Projects model will look like :
class Projects extends \yii\db\ActiveRecord
{
...
...
...
public static function isSavedInSession() { // why this is static is beyond this question context
if (Yii::$app->session->get('projects')) return true;
return false;
}
public function loadFromSession() {
if (Yii::$app->session->get('projects_name')) $this->name = if (Yii::$app->session->get('projects_name'));
if (Yii::$app->session->get('projects_account_id')) $this->account_id = if (Yii::$app->session->get('projects_account_id'));
...
... // insert all model's field here
...
}
public function saveToSession($fields) {
Yii::$app->session->set('projects', 1);
foreach ($fields as $field=>$value) {
Yii::$app->session->set('projects_' . $field, $value);
}
}
public function clearSession() {
Yii::$app->session->remove('projects'));
Yii::$app->session->remove('projects_name'));
Yii::$app->session->remove('projects_account_id'));
...
... // insert all model's field here
...
}
...
...
...
}
And in the AccountsController, just tell the program to jump back to projects/create if projects session is set, like so :
class AccountsController extends Controller
{
...
...
...
public function actionCreate($category)
{
$model = new Accounts();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
if (Projects::isSavedInSession()) {
return $this->redirect(['projects/create');
}
return $this->redirect(['index');
}
return $this->render('create', [
'model' => $model,
]);
}
...
...
...
}
Well, it's looks bit lengthy, but yeah, it's worth trying. Anyway, you could use this approach for another purpose, save current form state for example.
Oh, one more thing, i haven't tested this in real code, so if any error exposed on my code, hit me up in comment.
Happy coding. :)

Getting field value in controller

I want to get value of field in controller.
could you please help me?
here is my form code:
<?php
$form = ActiveForm::begin([
'id' => 'request-form',
'action' => 'site/request_page',
'method' => 'post',
'fieldConfig' => ['autoPlaceholder' => false]
]);
?>
<?= $form->field($model, 'workroom_id')->label(FALSE) ?>
and this is my controller code:
public function actionRequest_page() {
echo Yii::$app->request->post('workroom_id');
die();
}
But I got nothing in result.
write workroom_id in safe rule like this-
public function rules()
{
return [
[['workroom_id'],'safe']
];
}
Use bellow code -
echo Yii::$app->request->post('MODEL_NAME')['workroom_id'];
You should expand your action form-attribute. By using Url::to() for instance. As in echo \yii\helpers\Url::to(['site/request_page']);
And access your post data differently. Try var_dump(Yii::$app->request->post()); to see what your form data looks like. The other answer shows how to access it correctly.
The docs have an excellent starting place for working with forms.

Upload files and store titles into database

Controller :
class gallery extends CI_Controller {
function index()
{
$this->load->model('gallery_model');
if($this->input->post('upload'))
{
$this->gallery_model->do_upload();
}
$data['images'] = $this->gallery_model->get_images();
$this->load->view('gallery',$data);
}
}
Model :
<?php
class gallery_model extends CI_Model {
var $gallery_path;
var $gallery_path_url;
function gallery_model()
{
$this->gallery_path = realpath(APPPATH . '../images');
$this->gallery_path_url = base_url().'images/';
}
function do_upload()
{
$config = array(
'allowed_types' => 'jpeg|jpg|gif|png',
'upload_path' => $this->gallery_path
);
$this->load->library('upload', $config);
$this->upload->do_upload();
$image_data = $this->upload->data();
$config = array(
'source_image' => $image_data['full_path'],
'new_image' => $this->gallery_path. '/thumbs',
'maintain_ration' => TRUE,
'width' => 150,
'height' =>150
);
$this->load->library('image_lib', $config);
$this->image_lib->resize();
}
}
View:
<!DOCTYPE html>
<html>
<head>
<title>My gallery</title>
<meta charset="UTF-8"/>
</head>
<body>
<div id="upload">
<?php
echo form_open_multipart('gallery');
echo form_upload('userfile');
echo form_submit('upload','Upload');
echo form_close();
?>
</div>
</body>
</html>
I want to do something like an photo album. In the upload form i upload photos in images folder and the thumb into thumb folder. What i want to do is to store the titles of pictures into the database and retrieve from there and i don't know how to store the pictures titles.
I would add a text field to your form for Image Title, pass it to your do_upload method from the gallery model, or separately into a new image database model (to connect and query your database).
I'm writing this on the fly and is untested. Some advice to the process, make sure you are cleaning the inputs. Codeigniter does a great job at this, but it's good coding to share that advice. Also, you should like an image with its title. I would maybe also pass to the database, the dir path of the image and/or its thumb path. It also makes calling the image from gallery easier as you are already querying the Database for meta data. Something like a foreach($img in$result){ echo $img['title']." - ".echo $img['path'];} to produce "My title - http://example.com/images/thumb/1234.jpg"
View (input)
..
echo form_input('imgTitle', 'Image Title');
..
Controller
..
if($this->input->post('upload'))
{
$data['imgTitle'] = $this->input->post('imgTitle'); //Assigns the post value to the data array so you can pass it via $data to your views
$this->gallery_model->do_upload($data['imgTitle']);
}
..
Model
..
function do_upload($imgTitle=null) //passes a variable as NULL unless specified
{
..
$DB1 = $this->load->database(); //specify db connection/name
$data = array(
'title' => $imgTitle, //passed from controller
'name' => 'My Name');
$this->db->insert('mytable', $data);
..
}

Codeigniter 1-many db query on two tables which call for nested loops

I've read through a couple posts which are really close to the same question I am about to ask, but I'm still not grasping the MVC way. One example was close and titled "Codeigniter db query on two tables", but I'm getting the "Undefined property" errors which reinforces that fact I'm not calling objects properly. I would prefer not to use DataMapper simply because if I need to go out and get additional classes, then I might just go back to the procedural coding route. I was just a little excited on understanding how this framework implementation works.
I have two tables, lets call one "apps" and the other would be "mappings". "Apps" are applications which use apache as a reverse proxy configuration like this:
ProxyPass /mapping/ https:///
ProxyPassReverse /mapping/ https:///
Some of the apps could request multiple reverse proxy mappings, so its a 1-many design.
My objective is to use a select statement for the apps table then print out every column I desire from that table:
for example, I currently have two application defined in my "apps" table, in which one of the applications has two reverse proxy mappings,and the other has one. The prxypass lines below the data from the apps table would be coming from the apps_mapping table.
App: App ABC
Owner: ABC Team
Date Requested: 2013-10-27
ProxyPass /ABC-Resource/ https://<to-some-internal-URL>/
ProxyPassReverse /ABC-resource/ https://<to-some-internal-URL>/
App: App XYZ
Owner: XYZ Team
Date Requested: 2013-10-27
ProxyPass /XYZ-mapping/ https://<to-some-internal-URL>/
ProxyPassReverse /XYZ-mapping/ https://<to-some-internal-URL2>/
ProxyPass /anothermapp/ https://<to-some-internal-URL>/
ProxyPassReverse /anothermapping/ https://<to-some-internal-URL2>/
I've tried to model my first attempt of using CodeIgniter by way of modifying their tutorial provided by the CodeIgniter example in their user_guide.
Now what I haveis.
Model Class:
<?php
class Prp_model extends CI_Model {
public function __construct()
{
$this->load->database();
}
//GET APP THE ROWs FROM THE apps TABLE
public function get_appsUsingPrp()
{
$query = $this->db->get('apps');
return $query->result_array();
}
//GET THE MAPPINGS FROM THE apps_mappings TABLE
//FOR EACH APP BY WAY OF UNIQUE id IN THE appsTABLE
public function get_prpMappings($id = FALSE)
{
$query = $this->db->get_where('apps_mappings', array('resourceID' => $id));
return $query->result_array();
}
?>
for the above class, instead of using a return function on get_prpMappings() should I be putting it in a variable? Even then, how would one supply a value for the $id in the code called int he views page?
Controller Class
<?php
class Prp extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('prp_model');
}
public function index()
{
$data['apps'] = $this->prp_model->get_prp();
$data['mappings'] = $this->prp_model->get_prpMappings($id);
$data['title'] = 'PRP archive';
$this->load->view('templates/header', $data);
$this->load->view('prp/index', $data);
$this->load->view('templates/footer');
}
public function view($id)
{
$data['apps'] = $this->prp_model->get_prp();
$data['mappings'] = $this->prp_model->get_prpMappings($id);
}
}
View
<?php
print_r($apps);
print_r($mappings);
foreach ($apps as $details): ?>
<div id="main">
<ul>
<?php echo "<li>App Name: ".$details['app_name'] ?>
<?php echo "<li>EPRID: ".$details['EPRID'] ?>
<?php echo "<li>Requestor: ".$details['requestor'] ?>
<?php echo "<li>Team PDL: ".$details['PDL'] ?>
<?php foreach ($mappings as $map): ?>
<?php echo "<li>ProxyPass /".$map['resource']."/ ".$map['destURL'] ?>
<?php echo "<li>ProxyPassReverse /".$map['resource']."/ ".$map['destURL'] ?>
<?php endforeach ?>
</ul>
</div>
<hr />
<?php endforeach ?>
?>
Getting down to my confusion.... Should I be doing all the foreach looping in the model and/or the controller classes if I'm not going to setup the DataMapper Class?
Is there a way to call the get_prpMappings($id) function defined in the model class directly in the view? The only way for that function to work for me, is when the id of the app row is provided when iterating through the rows.
I tried putting $this->prp_model->get_prpMappings($id); in the view, but the view page doesn't seem to identify the class.
Lastly.. By the looks of it, it appears I would be doing more coding with a framework (such as CodeIgniter or Zend), then it would be to just write everything from scratch. But I'm under the impression the framework is to provide convenience down the road of additional coding. I'm just not seeing it. Please help.
UPDATED! I hope I understand this.
I have modified my logic to express the output desired. Would you be able to tell me if it is an inefficient way? Here is the logic:
MODEL CLASS:
<?php
class Prp_model extends CI_Model {
public function __construct()
{
$this->load->database();
}
//GET APP THE ROWs FROM THE sharedITG TABLE
public function get_appsUsingPrp()
{
$query = $this->db->get('sharedITG');
return $query->result_array();
}
//GET THE MAPPINGS FROM THE sharedITG_mappings TABLE
//FOR EACH APP BY WAY OF UNIQUE id IN THE shareITG TABLE
public function get_prpMappings($id = FALSE)
{
$this->db->select('resourceID, resource, destURL');
$query = $this->db->get_where('sharedITG_mappings', array('resourceID' => $id));
return $query->result_array();
}
public function get_prp()
{
//loop through all apps
foreach ($this->get_appsUsingPrp() as $app)
{
//print_r($app);
foreach ($this->get_prpMappings($app['id']) as $mappings)
{
$map[] = $mappings;
}
}
return $map;
}
}
Controller Class
<?php
class Prp extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('prp_model');
}
public function index()
{
$data['mappings'] = $this->prp_model->get_prp();
$data['apps'] = $this->prp_model->get_appsUsingPrp();
$data['title'] = 'PRP archive';
$this->load->view('templates/header', $data);
$this->load->view('prp/index', $data);
$this->load->view('templates/footer');
}
public function view($id)
{
$data['apps'] = $this->prp_model->get_appsUsingPrp();
$data['mappings'] = $this->prp_model->get_prp();
}
}
VIEW code:
<?php
//print_r($apps);
//print_r($mappings);
foreach ($apps as $details): ?>
<div id="main">
<ul>
<?php echo "<li>App Name: ".$details['app_name'] ?>
<?php echo "<li>EPRID: ".$details['EPRID'] ?>
<?php echo "<li>Requestor: ".$details['requestor'] ?>
<?php echo "<li>Team PDL: ".$details['PDL'] ?>
<?php
foreach ($mappings as $map)
{
if ($details['id'] == $map['resourceID'])
{
echo "<li>ProxyPass /".$map['resource']."/ ".$map['destURL'];
echo "<li>ProxyPassReverse /".$map['resource']."/ ".$map['destURL'];
}
}
?>
</ul>
</div>
<hr />
<?php endforeach ?>
So after further research, I found a forum that gave me a pretty decent example. I'm not sure if its the most optimal way to do this, but it worked for me and still (kind of) maintained the MVC model for Code igniter. The foreach in the function below is what I added. It appears it loops through the current result and obtains all rows for the second table that has a relationship between Table2ID and IDFromTable. Then adds the results by way of $result{$key}.
public function get_resuts()
{
$query = $this->db->get('table1');
$result = $query->result_array();
foreach ( $result as $key => $row )
{
$query = $this->db->get_where('Table2', array('Table2ID' => $row['IDFromTable']));
$row['DesiredFieldFromTable#'] = $query->result_array();
$result[$key] = $row;
}
return $result;
}
Then its available in the view by looping through the second array with the content from the foreach results in the get_resuts() function. I'm interested in learning of other ways to do this too.

Query is returning empty arrays in CakePHP (model and controller are set up)

I'm using Cake's find('all') method in the controller to query a table I have, and the requestAction method to use the controller function (and so to output the data) within the view. The problem is that the find method is returning empty arrays(ouput is 'ArrayArrayArray'). The table is named 'users' (as per Cake conventions) and the code for all three files are below:
Code for the view (test.ctp)
<?php
$users = $this->requestAction('/users/read');
foreach($users as $user) {
echo $user;
}
?>
Code for the controller (users_controller.php)
<?php
class UsersController extends AppController {
var $name = 'Users';
function read(){
$users = $this->User->find('all');
if(isset($this->params['requested'])) {
return $users;
}
}
}
?>
Code for the model (user.php)
<?php
class User extends AppModel {
var $name = 'User';
}
?>
I've dwindled it down and discovered that $users is being set to NULL by the $this->User->find('all') statement because that statement is actually not returning any values. I know Cake is finding the table because of a typo I had earlier with the table name ('usres' instead of 'users'). I can't figure out what I'm missing or what I'm doing wrong. Would love some help. :)
The ouput is 'ArrayArrayArray' doen't means itz empty
try
foreach($users as $user) {
debug($user);
}
For me this code is meaningless.
if you want to use requestAction() use it in the proper way. It's used to call (and print) the parts of the application in the view.
Here is how to achieve the working and correct code:
Your Users class:
class Users extends AppController {
function read(){
$this->set('users', $this->User->find('all'));
$this->layout = "ajax";
$this->render();
}
}
Your read.ctp:
<ul><?php
if(isset($users)){
foreach($users as $user) {
echo '<li>'.$user.'</li>';
}
}
?></ul>
Now in your test.ctp you need to call:
<?php echo $this->requestAction(
array(
'controller'=>'users',
'action'=>'read'
)
);?>
And you will see the result in your test action as unsorted list.