I am trying to create simple singleton in yii2 contoller. Maybe i misunderstood something about this pattern but i decide to try. So i have a CRUD. When i got one instance of that class in the db and i decide to update it, the $instance variable is empty(null). Is it because of the page reloading after the creation of the instance and that's why my static variable is set to null again? And is it even possible to make it like this or i am really, really on wrong way? Thank you in advance!
<?php
namespace backend\controllers;
use backend\models\DeliveryTime;
use yii\data\ActiveDataProvider;
use Yii;
class DeliveryTimeController extends \yii\web\Controller
{
public static $instance = null;
public function actionIndex()
{
$delivery = new ActiveDataProvider([
'query' => DeliveryTime::find()->where('id>0')
]);
return $this->render('index', ['delivery' => $delivery]);
}
public static function setInstance()
{
if(self::$instance == null){
self::$instance = new DeliveryTime();
}
return self::$instance;
}
public static function getInstance(){
return self::$instance;
}
public function actionCreate()
{
$delivery = DeliveryTimeController::setInstance();
if($delivery->load(Yii::$app->request->post()) && $delivery->save()){
self::$instance = $delivery;
return $this->redirect(['index']);
}
return $this->render('create', ['model' => $delivery]);
}
public function actionUpdate()
{
$delivery = DeliveryTimeController::getInstance();
if($delivery->load(Yii::$app->request->post()) && $delivery->save()){
return $this->render(['index']);
}
return $this->render('update', ['model' => $delivery]);
}
public function actionDelete(){
$delivery = DeliveryTimeController::getInstance();
if($delivery != null){
$delivery->delete();
return $this->redirect(['index']);
}
}
}
For design patterns i would recommend to check out
https://github.com/kamranahmedse/design-patterns-for-humans
https://github.com/edin/php-design-patterns (my github repo :)
For what you are trying it's better to just create new instance.
Related
My Code is Like This
public function function1(){
$client = new Google_Client();
$client->setAccessToken('Some value');
}
public funnction function2(){
// Here I want to get the token using $client->getAccessToken()
}
How can use the same instance of class from function1 in function2? So I can use $client->getAccessToken() in function2
Simple Solution use global
<?php
$client;
function function1(){
global $client;
$client = new Google_Client();
$client->setAccessToken('Some value');
}
function function2(){
global $client;
$token=$client->getAccessToken();
}
?>
It's simple but not recommended. It's never a good Idea to use a global variables, we must avoid it as long as possible.
So there must be some other way,right ?
well yes use class
<?php
class ForClient {
private $client;
function __construct(){
$client = new Google_Client();
}
public function setToken($val){
$client->setAccessToken($val);
}
public function getToken(){
$token=$client->getAccessToken();
return $token;
}
}
$token_handler = new ForClient();
$token_handler->setToken(25);
$token=$token_handler->getToken();
?>
I changed the function names to make code more readable.
the error :
Action App\Http\Controllers\formController#form not defined. (View: C:\xampp\htdocs\ucar3\resources\views\layouts\Form.blade.php) (View: C:\xampp\htdocs\ucar3\resources\views\layouts\Form.blade.php)
I tried changing the route in web.php
web.php
Route::resource('Inscription','inscriController');
Controller
class FormController extends Controller
{
public function show()
{
return view('pages.Inscription');
}
public function insert(Request $request)
{
$Cin = $request->input('Cin');
$nom = $request->input('nom');
$prenom = $request->input('prenom');
$email = $request->input('email');
$telephone = $request->input('telephone');
$specialite = $request->input('specialite');
$typedediplome = $request->input('typedediplome');
$mentiondiplome = $request->input('mentiondiplome');
$redoublement = $request->input('redoublement');
$communication = $request->input('communication');
$publication = $request->input('publication');
$experiencePedagogiqueSecondaire = $request
->input('experiencePedagogiqueSecondaire');
$experiencePedagogiqueSupérieur = $request
->input('experiencePedagogiqueSupérieur');
$data = array(['Cin'=>$Cin,
'nom'=>$nom,
'prenom'=>$prenom,
'email'=>$email,
'telephone'=>$telephone,
'specialite'=>$specialite,
'typedediplome'=>$typedediplome,
'mentiondiplome'=>$mentiondiplome,
'redoublement'=>$redoublement,
'communication'=>$communication,
'publication'=>$publication,
'experiencePedagogiqueSecondaire'=>$experiencePedagogiqueSecondaire,
'experiencePedagogiqueSupérieur'=>$experiencePedagogiqueSupérieur
]);
DB::table('users')->insert($data);
return view('pages.success');
}
}
Model
class form extends Model
{
public $table = "form";
protected $fillable = [
'Cin',
'nom',
'prenom',
'telephone',
'email',
'specialite',
'typedediplome',
'mentiondiplome',
'redoublement',
'communication',
'publication',
'experiencePedagogiqueSecondaire',
'experiencePedagogiqueSupérieur'
];
public $timestamps = true;
}
As the Error says
formController#form not defined.
but in your class you've
FormController extends Controller
Please check if you are calling FormController with lower case 'F'.
I think you have problems with your inscriController and your routes, use the following code:
web.php
use App\Http\Controllers\inscriController;
Route::resource('Inscription', inscriController::class);
app/Http/Controllers.php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class inscriController extends Controller {
public function __construct() {
$this->middleware('auth');
}
}
Check if you set the correct namespace in the FormController.php
You are also missing a function form inside your FormController.
public function getResource() {
return $this->hasOne(User::className(), ['id' => 'resource_id']);
}
this function working fine but when i use this
public function getResource() {
$model = ucfirst($this->resource_type);
return $this->hasOne($model::className(), ['id' => 'resource_id']);
}
its give me error "Class 'User' not found".
Thanks
you have to use the name including namespace if you specify it dynamically.
public function getResource() {
$model = "api\\models\\".ucfirst($this->resource_type);
return $this->hasOne($model::className(), ['id' => 'resource_id']);
}
I want to implement user login into yii2 basic app.everything works properly except, when I tries to access Yii::$app->user->isGuest on layout main page. it always returns true. whats going wrong here?, please help me
public function actionLogin()
{
if (!Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
Yii::$app->user->isGuest; // i m getting this as false, which is correct, but after goBack(), I m getting it as true
return $this->goBack();
}
return $this->render('login', [
'model' => $model,
]);
}
Login Mehod from LoginForm.php
public function login()
{
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
}
return false;
}
Note : I am using custom theme, which rests outside the web folder and inside project/themes/ directory
** User Model is as follows**
<?php
namespace app\models;
use Yii;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
use yii\web\NotFoundHttpException;
class User extends ActiveRecord implements IdentityInterface {
private $id;
private $authKey;
const STATUS_DELETED = '0';
const STATUS_ACTIVE = '10';
public static function tableName() {
return '{{%user}}';
}
/**
* #inheritdoc
*/
public function behaviors() {
return [
TimestampBehavior::className(),
];
}
/**
* #inheritdoc
*/
public function getId() {
return $this->id;
}
/**
* #inheritdoc
*/
public function getAuthKey() {
return $this->authKey;
}
/**
* #inheritdoc
*/
public function validateAuthKey($authKey) {
return $this->authKey === $authKey;
}
/**
* Validates password
*
* #param string $password password to validate
* #return boolean if password provided is valid for current user
*/
public function validatePassword($password) {
return Yii::$app->security->validatePassword($password, $this->password_hash);
}
public static function findByEmail($email) {
$user_type = ['U'];
return static::find()
->andWhere('email = :email', [':email' => $email])
->andFilterWhere(['in', 'user_type', $user_type])
->one();
}
public static function findIdentity($id) {
$user = static::find()->where(['id' => $id, 'status' => self::STATUS_ACTIVE,])->one();
if (empty($user->id)) {
\Yii::$app->session->destroy();
}
return $user;
}
public static function findIdentityByAccessToken($token, $type = null) {
$user = static::find()
->where([
'access_token' => $token,
'status' => self::STATUS_ACTIVE,
])
->one();
if (!empty($user)) {
return $user;
} else {
throw new NotFoundHttpException('Invalid access token.');
}
}
}
Remove the lines:
private $id;
private $authKey;
from User class.
You should not directly declare ActiveRecord attributes that come from database as stated in the Guide.
Note: The Active Record attributes are named after the associated table columns in a case-sensitive manner. Yii automatically defines an attribute in Active Record for every column of the associated table. You should NOT redeclare any of the attributes.
I test a config class, which is parsing a config file and allows me to get the various settings for an app.
My goal is to mock the parse() method of the Config class, which is called in the constructor and to set what this method is returning in the constructor.
This way, it prevents file_get_contents() from being called (in the parse() method) and enables me to have a Config class with the config property already set to contain an array of properties.
But I haven't succeeded doing that.
Here is the code:
The config class:
<?php namespace Example;
use Symfony\Component\Yaml\Parser;
class Config
{
private $parser;
private $config;
public function __construct(Parser $parser, $filePath)
{
$this->parser = $parser;
$this->config = $this->parse($filePath);
}
public function parse($filePath)
{
$fileAsString = file_get_contents($filePath);
if (false === $fileAsString) {
throw new \Exception('Cannot get config file.');
}
return $this->parser->parse($fileAsString);
}
public function get($path = null)
{
if ($path) {
$config = $this->config;
$path = explode('/', $path);
foreach ($path as $bit) {
if (isset($config[$bit])) {
$config = $config[$bit];
}
}
return $config;
}
return false;
}
}
The test:
<?php namespace Example;
class ConfigTest extends \PHPUnit_Framework_TestCase
{
private function getConfigTestMock($configAsArray)
{
$parser = $this->getMockBuilder('\Symfony\Component\Yaml\Parser')
->getMock();
$configMock = $this->getMockBuilder('Example\Config')
->setConstructorArgs([$parser, $configAsArray])
->setMethods(['parse', 'get'])
->getMock();
$configMock->expects($this->once())
->method('parse')
->willReturn($configAsArray);
return $configMock;
}
/**
* #test
*/
public function get_returns_false_if_no_path_given()
{
$configMock = $this->getConfigTestMock(['param1' => 'value1']);
// Testing further...
}
}
I suggest you to make a functional test mocking the interaction with the file system, without do partial mocking of the tested class.
I recently discover the vfsStream library used in a great article of William Durand about Symfony2 and DDD.
So you can install this library in your composer.json (I tested the solution with the 1.4 version) and try this example test class:
<?php
namespace Acme\DemoBundle\Tests;
use Acme\DemoBundle\Example\Config;
use org\bovigo\vfs\vfsStream;
use Symfony\Component\Yaml\Parser;
class ConfigTest extends \PHPUnit_Framework_TestCase
{
/**
* #test
*/
public function valid_content()
{
$content = "param1: value1";
$root = vfsStream::setup();
$file = vfsStream::newFile('example.txt')
->withContent($content)
->at($root);
$filepath = $file->url();
$parser = new Parser();
$config = new Config($parser, $filepath);
$this->assertEquals("value1", $config->get("param1"));
}
}
Hope this help
For test the Config class you need to mock only the Parser and use the real Config class. As Example:
<?php
namespace Acme\DemoBundle\Tests;
use Acme\DemoBundle\Example\Config;
class ConfigTest extends \PHPUnit_Framework_TestCase
{
private function getConfigTestMock($configAsArray)
{
$parser = $this->getMockBuilder('\Symfony\Component\Yaml\Parser')
->getMock();
$parser->expects($this->once())
->method('parse')
->willReturn($configAsArray);
$configMock = new Config($parser,"fakePath");
return $configMock;
}
/**
* #test
*/
public function get_returns_false_if_no_path_given()
{
$configMock = $this->getConfigTestMock(['param1' => 'value1']);
$this->assertEquals("value1",$configMock->get("param1"));
// Testing further...
}
}
Hope this help