Yii2 function based on relation gives error on create - php

I have this in my model called B:
public function getA() {
return $this->hasOne(\app\models\A::className(), ['id' => 'A_Id']);
}
public function getDispName() {
return $this->a->attr . ' ' . $this->attr . ' ' . $this->attr2;
}
works everything fine, until I go to Create. Then I get the following "error":
PHP Notice – yii\base\ErrorException Trying to get property of non-object
As a workaround I have done this:
public function getDispName() {
if (is_object($this->a)) {
return $this->a->attr . ' ' . $this->attr . ' ' . $this->attr2;
}
}
I'm not sure if this is a good solution, or why do I get this "notice" only at create, but I would like to understand and do it correctly. I don't want this to cause problems somewhere else. Maybe I miss something other basic and important knowledge. If you have any ideas, I would be grateful to hear it. Thanks.

You are probably trying to use a B model that does not have a A model attached. If that is the case of course your function would fail. Are you sure for every B you have an A? Probably you are inserting a B and not inserting an A and trying to show info on it.
Your options are:
1) do exactly like you did, maybe change it to
public function getDispName() {
$display = '';
if (is_object($this->a)) {
$display = $this->a->attr;
}
return $display . ' ' . $this->attr . ' ' . $this->attr2;
}
2) fix your code to always make sure you insert an A when you insert a B. It can be an empty record but it has to be a record.

This property is based on others properties, so when you create new object of type A you don't need to indicate this property. Indicate only fields from which it consists.
Open /views/model_name/_form.php and delete row with property dispName
<?= $form->field($model, 'dispName')->textInput() ?> // or textarea or ...

Related

System of logs for my site

I create a small class for save the logs of my website. My log class :
class Logs {
public static function writeFile($message)
{
$log_path = '/home/vagrant/Workspace/symfony/app/logs';
// Set path:
$log_path .= '/' . date('Ymd');
$log_path .= '.log';
$s_message = date("Y-m-d H:i:s") . ' (' . microtime(true) . ') ' . $message;
$s_message .= "\n";
file_put_contents($log_path, $s_message, FILE_APPEND);
}
public static function logInfo($s_message)
{
self::writeFile($s_message);
}
}
And I call the static method in my controller :
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$categories = $em->getRepository('EnsJobeetBundle:Category')->getWithJobs();
$test = array(
'1'=>'1',
'2'=>'2',
'3'=>'3'
);
Logs::logInfo(print_r($test));
return $this->render('EnsJobeetBundle:Job:index.html.twig', array(
'categories' => $categories
));
}
The problem is that : in my view it's show this $test array and in my log is write only the first value of array, so the value 1.
What I'm doing wrong? Help me please! Thx in advance!
In accordion with the doc:
If you would like to capture the output of print_r(), use the return
parameter. When this parameter is set to TRUE, print_r() will return
the information rather than print it.
Use this:
Logs::logInfo(print_r($test, true));
instead of:
Logs::logInfo(print_r($test));
hope this help
I suggest you to use Monolog for this task
http://symfony.com/doc/current/cookbook/logging/monolog.html
print_r has second parameter: return. Wich means will print_r() returns it's output, or just display it. It's false by default
So you need to try
Logs::logInfo(print_r($test,true));

Zend framework 2: Form bind not setting the values extracted from database

I want to create a form with Zend Framework 2 for my application and I have everything in place and the form is getting displayed but my issue is I am not able to bind the initial form values that come from the database
$myUserDetails = <details of my user coming from DB>;
$form = $form->bind($myUserDetails); //This should set the values for the form to display but it doesnt
My display logic is simple as shown below
$form = $this->form;
$form->setAttribute('action',
$this->url('<routename>',array('action'=>'<actionname>')));
$form->prepare();
echo $this->form()->openTag($form) . PHP_EOL;
echo $this->formRow($form->get('email_id')) . PHP_EOL;
echo $this->formRow($form->get('dob')) . PHP_EOL;
echo $this->formRow($form->get('gender')) . PHP_EOL;
echo $this->formRow($form->get('user_page_name')) . PHP_EOL;
echo $this->formInput($form->get('submit')) . PHP_EOL;
echo $this->form()->closeTag($form) . PHP_EOL;
Now I tried to set the data from my object that I bind to the form in my controller action
$myUserDetails = <details of my user coming from DB>;
$form = $form->bind($myUserDetails);
$data = $myUserDetails->getArrayCopy();
$form->setData($data['data']);
This seems to work somehow and is displaying my values in the view. So i just want to know what have I done wrong in my first approach? Thanks in advance :)
Thanks to #Stoyan Dimov I solved the issue. Basically it was with getArrayCopy function in my model as I was direcly returning an array which was enclosed in an index 'data'
So I changed my getArrayCopy to
public function getArrayCopy() {
$data = get_object_vars($this);
return $data['data'];
}
And voila it worked.
Thanks again Stoyan Dimov

Warning: Missing Argument 1

I am having some problems with my php code: All information returns but I cannot figure out why I am getting the error. For my index page I only inluded the line of code that is actually using that class there really is no other code other than some includes. Im sure it is how I built my __contstruct but i am not sure of the approriate way of doing it. I am missing something in how it is being called from the index page.
This line of code for my __construct works w/o error but I do not want the variable assigned in my class.
public function __construct(){
$this->user_id = '235454';
$this->user_type = 'Full Time Employee';
}
This is my Class
<?php
class User
{
protected $user_id;
protected $user_type;
protected $name;
public $first_name;
public $last_name;
public $email_address;
public function __construct($user_id){
$this->user_id = $user_id;
$this->user_type = 'Full Time Employee';
}
public function __set($name, $value){
$this->$name = $value;
}
public function __get($name){
return $this->$name;
}
public function __destroy(){
}
}
?>
This is my code from my index page:
<?php
ini_set('display_errors', 'On');
error_reporting(E_ALL);
$employee_id = new User(2365);
$employee_type = new User();
echo 'Your employee ID is ' . '"' .$employee_id->user_id. '"' . ' your employement status is a n ' . '"' .$employee_type->user_type. '"';
echo '<br/>';
?>
The problem is:
$employee_type = new User();
the constructor expect one argument, but you send nothing.
Change
public function __construct($user_id) {
to
public function __construct($user_id = '') {
See the outputs
$employee_id = new User(2365);
echo $employee_id->user_id; // Output: 2365
echo $employee_id->user_type; // Output: Full Time Employee
$employee_type = new User();
echo $employee_type->user_id; // Output nothing
echo $employee_type->user_type; // Output: Full Time Employee
If you have one user, you can do this:
$employer = new User(2365);
$employer->user_type = 'A user type';
echo 'Your employee ID is "' . $employer->user_id . '" your employement status is "' . $employer->user_type . '"';
Which output:
Your employee ID is "2365" your employement status is "A user type"
I'm no PHP expert, but it looks like you are creating 2 new instances of class user, and on the second instatiation, you are not passing the user_id into the constructor:
$employee_id = new User(2365);
This, it would seem to me, is creating a new instance of User and assigning this instance to the variable $employee_id - I don't think this is what you want though?
$employee_type = new User();
This looks like you're instantiating another instance of User and assigning it to variable $employee_type - but you have called the constructor User() without passing in an ID as is required - hence the error (missing argument).
The reason your return script contents look OK is because the first instance of the User class has an ID (because you passed it in) and the second one has an employee type because this is set in the constructor.
Like I say, I don't know PHP but I'm guessing you want something more along the lines of:
$new_user = new User(2365);
echo 'Your employee ID is ' . '"' .$new_user->user_id. '"' . ' your employement status is a n ' . '"' .$new_user->employee_type. '"';
Here, you are instantiating a single instance of your user class assigned to the variable $new_user, and then accessing the properties of that single instance.
EDIT: .....Aaaaaaaaand - I was too slow :-)

processing mysql assoc results through various classes

Hi I've recently started yet another project and my boss is insisting that we use the MVC model, the problem being that due to many articles showing different ways to do this we havent managed to agree on what a proper MVC model should look like.
So here's my problem for this project (whether this is the correct way to do it or not) I am using the following baseline rules
Controller classes manage both getting the data from the model classes and passing the data to the view classes and retrieving the view and displaying it
Model classes managhe all database actions and return the data using mysql_fetch_assoc
View classes create the views using the data etc.
So my issue is with processing the information from mysql_fetch_assoc normally you would do something like this (assuming we have already run a query)
while ($row = mysql_fetch_assoc($result)) {
echo $row["username"];
}
but as I'm processing the results in the view class rather than the model how do I cycle through all of the results when I have already passed the assoc array to the view, currently I'm getting a problem where it keeps looping through the results until it hits a memory size error so for some reason it isn't able to figure out how many results it needs to cycle through
My current code snippets are below sorry for the bad explainations.
Controller
require_once 'admin_model.php';
require_once 'admin_view.php';
class admin_controller {
public $model;
public $view;
public function __construct() {
$this->model = new admin_model;
$this->view = new admin_view;
}
public function get_group_view() {
$in_model = $this->model->get_group_view();
$in_view = $this->view->get_group_view ($in_model);
echo $in_view;
}
Model
class admin_model {
public function get_group_view() {
$query = mysql_query("
SELECT
group_id,
group_name
FROM
user_groups
");
return mysql_fetch_assoc($query);
}
}
View
class admin_view {
public function get_group_view($group_data) {
while($group_data) {
$output .= $group_data['group_id'] . '###' . $group_data['group_name'] . '<hr />';
}
return $output;
}
}
Which currently returns the error:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 133693393 bytes)
So can someone please advise me on the best way to go through the results without moving 'mysql_fetch_assoc' function from the model class?
PS I know I'm probably doing MVC completely wrong but it works for us and we don't want to have to research and change our code yet again thanks.
You should not return the MySQL Result - you should do:
$return = array();
$query = mysql_query("SELECT group_id, group_name FROM user_groups");
while($row = mysql_fetch_assoc($query)) {
$return[] = $row;
}
mysql_free_result($row);
return $return;
And you should fix the $group_data bug per #Roman_S . The correct use, along with the above code is
public function get_group_view($group_data) {
$output = '';
foreach($group_data as $group) {
$output .= $group['group_id'] . '###' . $group['group_name'] . '<hr />';
}
return $output;
}
Finally you should migrate to MySQLi or PDO if possible.
You have en error here
while($group_data) {
$output .= $group_data['group_id'] . '###' . $group_data['group_name'] . '<hr />';
}
If $group_data is not empty - your loop will never end.
To give a suggestion on how to handle database control.
When using PDO for instance
$pdoInst = new PDO( .. );
and we have a method somewhere that validates every statement the $pdoInst produces
abstract class .. {
public static function validateStmt($stmt) {
if($stmt !== false) { .. }
// everything else you like, even error handling, log files, etc.
}
}
}
a prepared statement like the get_group_view method will look like the following
public function get_group_view {
$stmt = $pdoInst->prepare(" .. QUERY .. ");
// the return can be wrapped in a method to handle errors, etc, which can be done
// here or else where.
$stmt->execute() // returns true or false
return $stmt;
}
now for iteration
public function get_group_view($group_data) {
$output = "";
// validate the statement, can be done here or else where as said before
if($pdoInst::validateStmt($group_data)) {
// many ways how to iterate, foreach is just one.
foreach($group_data as $index => $group) {
$output .= $group['group_id'] . '###' . $group['group_name'] . '<hr />';
}
}
return $output;
}
The nicest thing about PDO is that you can extend the classes with custom ones. You can add functionality that adds more value to your Model.

PHP Class variable access question

I'm having trouble accessing a class' variable.
I have the functions below in the class.
class Profile {
var $Heading;
// ...
function setPageTitle($title)
{
$this->Heading = $title;
echo 'S: ' . $this->Heading;
}
function getPageTitle2()
{
echo 'G: ' . $this->Heading;
return $this->Heading;
}
// ...
}
Now when I run the method $this->setPageTitle("test") I only get
G: S: test
What's wrong with the getPageTitle2 function? Heading is public btw. Please help!
Thanks guys!
Now when I run the method $this->setPageTitle("test") I only get
G: S: test
That sounds implausible. Are you sure you're not running:
$this->getPageTitle2();
$this->setPageTitle("test");
PHP - like most programming languages - is an imperative language. This means that the order in which you do things matters. The variable $this->Header is not set at the time where you call getPageTitle2.
If you have "G: S: test"
it means you called getPageTitle2 before setPageTitle !
It looks normal then : I suggest first set then get.
you have to declare the Heading and title out of the function ... i dont know if you already did that
see the order of calling the functions
class Profile {
var $Heading;
// ...
function setPageTitle($title)
{
$this->Heading = $title;
echo 'S: ' . $this->Heading;
}
function getPageTitle2()
{
echo 'G: ' . $this->Heading;
return $this->Heading;
}
// ...
}
I am guessing you are doing something like this:
$profile = new Profile();
$profile->setPageTitle("test");
$profile->getPageTitle2();
and that this would result in the following output:
S: testG: test
and that if you echo $profile you will just get
test
so what do you think is the problem or what are you not accomplishing that you want to?
also I would probably declare $Heading as
private $heading;

Categories