I'm new to oop and MVC and I'm trying to test the flow between my index, controller, and model files. All of the test functions work except for 'check status'. What's the problem? The function is highlighted in BOLD. (INDEX)
$Controller = new Controller;
$Controller->ShowRegisterLogin();
?> (CONTROLLER)
Class Controller {
function ShowRegisterLogin() {
echo 'ShowRegisterLogin Function works';
$Model = new Model;
$Model->TestModel();
**$Model->checkStatus();**
}
}
?>
(MODEL)
class Model {
Var $Status = 'return works';
function TestModel() {
echo 'Test Model Works';
}
**function checkStatus() {
return $this->Status;
}**
}
?>
You need to echo the value if you want to see it
echo $Model->checkStatus();
Otherwise, nothing gets done with the return value and it disappears.
Related
If I create a class with PHP7 multiple times, it seems it is returning always the same class instead of returning a new one each time.
For example:
function createAClass()
{
return new class
{
public static $foo=0;
};
}
$class = createAClass();
$class::$foo = 3;
echo "class:".$class::$foo."<br>";
$anotherClass = createAClass();
echo "anotherClass:".$anotherClass::$foo."<br>";
This is the output:
class:3
anotherClass:3
I though the output should be 3 and 0. What's happening? Is this a bug, or a "feature" of PHP 7? :)
btw, I was trying to use this to test a trait with static methods with PHPUnit.
I've found the documentation and it seems it is the expected behaviour:
http://php.net/manual/en/language.oop5.anonymous.php
All objects created by the same anonymous class declaration are instances of that very class.
But I needed to create a function which returned a different class each time it was called, so I came with this solution:
function createAClass()
{
$class = null;
$stamp = random_int(PHP_INT_MIN ,PHP_INT_MAX);
echo "stamp: $stamp\n";
$classcode = <<< EOT
\$class = new class {
public static \$differentiate='$stamp';
// YOUR CODE HERE
};
EOT;
echo "Source code of class:\n$classcode\n\n";
eval($classcode);
return $class;
}
$class = createAClass();
$anotherClass = createAClass();
if (get_class($class) === get_class($anotherClass)) {
echo 'same class';
} else {
echo 'different class';
}
I have advanced app. I create CRUD for User model. So i got update action. I tried to update password by adding
<?= $form->field($model, 'password')->passwordInput() ?>
But it call error, something like "password is write-only variable"
I tried to use field
<?= $form->field($model, 'new_password')->passwordInput() ?>
With adding in actionUpdate model->setPassword($this->new_password); and it throw Getting unknown property: common\modules\user\controllers\DefaultController::new_password.
But model->setPassword('123456'); successfully setting pussword 123456.
How can i get new_password field from view, to put it in model->setPassword('there');
Or maybe exist best way to do it?
UPD
I tried do it. Is not work.
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
if ($this->new_password) {
$this->setPassword($this->new_password);
}
return true;
} else {
return false;
}
}
UPD2
public function setPassword($password) {
$this->password_hash = Yii::$app->security->generatePasswordHash($password);
}
And password_hash writing in database. I can easy change hash, via generated CRUD, but don't know how to use setPassword() in updateAction.
You can try write updatePassword function like setPassword with another variable
public function updatePassword($new_password) {
$this->password_hash = Yii::$app->security->generatePasswordHash($new_password);
}
declare a variable
public $new_password;
And add it in rules()
public function rules() {
return [
//...
['new_password', 'required'],
['new_password', 'string', 'min' => 6],
];
}
And at actionUpdate in your controller add
$model->updatePassword($model->new_password);
This should help
Here "$this" is your Controller which of course, doesn't have 'new_password' property. You'd better not set new password in controller, but do it in model, for example in beforeSave method:
if ($this->new_password) {
$this->setPassword($this->new_password);
}
i have created new widget to display information in admin view. Final view must be same as CGridView, but with different logic for columns. Everything works fine, except when i try to call CButtonColumn column.
foreach ($this->columns as $column) {
if (is_array($column) && isset($column['class']) {
$this->renderColumnWidget($column);
}
}
/* ... */
protected function renderColumnWidget($column)
{
$widgetClass = $column->class;
unset($column->class);
if (strpos($widgetClass, '.') === false) {
$widgetClass = 'zii.widgets.grid.'.$widgetClass;
}
$this->widget($widgetClass, $column); // Error from here
}
So basically here i check if there is class attribute in column and call that widget. But i get error: CButtonColumn and its behaviors do not have a method or closure named "run".
What am i doing wrong? CButtonColumn don't have run method, and i don't want to extend this class.
You this as a function like this to initiate your columns
protected function initColumns(){
foreach($this->columns as $i=>$column) {
if(is_string($column))
$column=$this->createDataColumn($column);
else {
if(!isset($column['class']))
$column['class']='CDataColumn';
$column=Yii::createComponent($column, $this);
}
if($column->id===null)
$column->id=$id.'_c'.$i;
$this->columns[$i]=$column;
}
foreach($this->columns as $column)
$column->init();
}
i want to change default action of a controller depends on which user is logged in.
Ex. There are two users in my site : publisher and author and i want to set publisher action as default action when a publisher is logged in, and same for author.
what should i do? when can I check my roles and set their relevant actions?
Another way to do this would be setting the defaultAction property in your controller's init() method. Somewhat like this:
<?php
class MyAwesomeController extends Controller{ // or extends CController depending on your code
public function init(){
parent::init(); // no need for this call if you don't have anything in your parent init()
if(array_key_exists('RolePublisher', Yii::app()->authManager->getRoles(Yii::app()->user->id)))
$this->defaultAction='publisher'; // name of your action
else if (array_key_exists('RoleAuthor', Yii::app()->authManager->getRoles(Yii::app()->user->id)))
$this->defaultAction='author'; // name of your action
}
// ... rest of your code
}
?>
Check out CAuthManager's getRoles(), to see that the returned array will have format of 'role'=>CAuthItem object, which is why i'm checking with array_key_exists().
Incase you don't know, the action name will be only the name without the action part, for example if you have public function actionPublisher(){...} then action name should be: publisher.
Another, simpler, thing you can do is keep the default action the same, but that default action simply calls an additional action function depending on what kind of user is logged in. So for example you have the indexAction function conditionally calling this->userAction or this->publisherAction depending on the check for who is logged in.
I think you can save "first user page" in user table. And when a user is authenticated, you can load this page from database. Where you can do this? I think best place is UserIdentity class. After that, you could get this value in SiteController::actionLogin();
You can get or set "first page" value:
if (null === $user->first_page) {
$firstPage = 'site/index';
} else {
$firstPage = $user->first_page;
}
This is a complete class:
class UserIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{
$user = User::model()->findByAttributes(array('username' => $this->username));
if ($user === null) {
$this->errorCode = self::ERROR_USERNAME_INVALID;
} else if ($user->password !== $user->encrypt($this->password)) {
$this->errorCode = self::ERROR_PASSWORD_INVALID;
} else {
$this->_id = $user->id;
if (null === $user->first_page) {
$firstPage = 'site/index';
} else {
$firstPage = $user->first_page;
}
$this->errorCode = self::ERROR_NONE;
}
return !$this->errorCode;
}
public function getId()
{
return $this->_id;
}
}
/**
* Displays the login page
*/
public function actionLogin()
{
$model = new LoginForm;
// if it is ajax validation request
if (isset($_POST['ajax']) && $_POST['ajax'] === 'login-form') {
echo CActiveForm::validate($model);
Yii::app()->end();
}
// collect user input data
if (isset($_POST['LoginForm'])) {
$model->attributes = $_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
if ($model->validate() && $model->login())
$this->redirect(Yii::app()->user->first_page);
}
// display the login form
$this->render('login', array('model' => $model));
}
Also, you can just write right code only in this file. In SiteController file.
I have the following PHP code;
<?php
component_customer_init();
component_customer_go();
function component_customer_init()
{
$customer = Customer::getInstance();
$customer->set(1);
}
function component_customer_go()
{
$customer = Customer::getInstance();
$customer->get();
}
class Customer
{
public $id;
static $class = false;
static function getInstance()
{
if(self::$class == false)
{
self::$class = new Customer;
}
else
{
return self::$class;
}
}
public function set($id)
{
$this->id = $id;
}
public function get()
{
print $this->id;
}
}
?>
I get the following error;
Fatal error: Call to a member function set() on a non-object in /.../classes/customer.php on line 9
Can anyone tell me why I get this error? I know this code might look strange, but it's based on a component system that I'm writing for a CMS. The aim is to be able to replace HTML tags in the template e.g.;
<!-- component:customer-login -->
with;
<?php component_customer_login(); ?>
I also need to call pre-render methods of the "Customer" class to validate forms before output is made etc.
If anyone can think of a better way, please let me know but in the first instance, I'd like to know why I get the "Fatal error" mentioned above.
Well, I think your Customer::getInstance() method is flawed. It should look like this:
...
static function getInstance()
{
if(self::$class == false)
{
self::$class = new Customer;
return self::$class; // ADDED!!
}
else
{
return self::$class;
}
}
....
In the if(self::$class == false) branch you are creating the instance of the class, but you dont return it.
You could also rewrite it as such:
static function getInstance()
{
if(self::$class == false)
{
self::$class = new Customer;
}
return self::$class;
}
To make it a bit shorter.
DRY: Don't Repeat Yourself
static function getInstance()
{
if(self::$class == false)
{
self::$class = new Customer;
}
return self::$class;
}
And for Sinlgetons it is also important to prevent __clone() from being used. Making it private should solve that problem:
private function __clone() {}