Change the variable before saving Yii2 rest - rest

When adding an entry through the rest api how to change a variable before save values?
Below is a part of the controller code:
class RestusersController extends ActiveController
{
public $modelClass = 'app\models\User';
public function actions()
{
$actions = parent::actions();
$actions['index']['prepareDataProvider'] = [$this, 'prepareDataProvider'];
return $actions;
}
public function prepareDataProvider()
{
return new ActiveDataProvider([
'query' => User::find()->where(['status_id'=>'1']),
'pagination' => false,
]);
}
}

eg change the variable $ this-> status_id = 1;
public function beforeSave($insert)
{
$this->status_id = 1;
return parent::beforeSave($insert);
}

Related

TYPO3 Repository query returns uid and pid but no other fields

I'm doing a query on a really simple table in a typo 3 task. However, only the fields "uid" and "pid" are returned, the other fields are NULL.
My Entity:
<?php
namespace Name\SampleExtension\Domain\Model;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
class MailAgent extends AbstractEntity
{
/**
* #var integer
*/
protected $uid;
/**
* #var string
*/
protected $customeremail;
/**
* #var string
*/
protected $searchparameters;
/**
* #var string
*/
protected $resultlist;
public function getUid()
{
return $this->uid;
}
public function setCustomerEmail($customeremail)
{
$this->customeremail = $customeremail;
}
public function getCustomerEmail()
{
return $this->customeremail;
}
public function setSearchParameters($searchparameters)
{
$this->searchparameters = $searchparameters;
}
public function getSearchParameters()
{
return $this->searchparameters;
}
public function setResultList($resultlist)
{
$this->resultlist = $resultlist;
}
public function getResultList()
{
return $this->resultlist;
}
}
?>
The Repository:
<?php
namespace Name\SampleExtension\Domain\Repository;
use TYPO3\CMS\Extbase\Persistence\Repository;
class MailAgentRepository extends Repository
{
public function findByUids($uids)
{
$query = $this->createQuery();
foreach ($uids as $uid) {
$constraints[] = $query->equals('uid', $uid);
}
return $query->matching(
$query->logicalOr(
$constraints
)
)->execute();
}
}
?>
And the query inside the task:
<?php
namespace Name\SampleExtension\Task;
use TYPO3\CMS\Scheduler\Task\AbstractTask;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use Name\SampleExtension\Domain\Model\MailAgent;
use Name\SampleExtension\Domain\Repository\MailAgentRepository;
class MailAgentCheckup extends AbstractTask
{
public function execute() {
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$this->MailAgentRepository = $objectManager->get(MailAgentRepository::class);
$query = $this->MailAgentRepository->createQuery();
$allCustomers = $this->MailAgentRepository->findAll();
foreach ($allCustomers as $customer) {
var_dump($customer);
}
return true;
}
}
?>
I have no idea why the other fields are not returned, but the uid and the pid are. My guess is that I need to declare the mapping somewhere else.
EDIT: Heres the content of my TCA, which is probably wrong or not enough, but since I'm working on a existing extension I was copying from the TCA's of the tables that work.
tx_sampleextension_domain_model_mailagent.php
return [
'columns' => [
'uid' => [],
'customer_email' => [],
'search_parameters' => [],
'result_list' => [],
],
'types' => [],
];
This is from another table for which querys etc work
return [
'columns' => [
'immovable' => [],
'type' => [],
'title' => [],
'path' => [],
'mark_to_delete' => [],
],
];
Give a try to inject your repository
<?php
namespace Name\SampleExtension\Task;
use TYPO3\CMS\Scheduler\Task\AbstractTask;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use Name\SampleExtension\Domain\Model\MailAgent;
use Name\SampleExtension\Domain\Repository\MailAgentRepository;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
class MailAgentCheckup extends AbstractTask
{
/**
* mailAgentRepository
*
* #var \Name\SampleExtension\Domain\Repository\MailAgentRepository
* #inject
*/
protected $mailAgentRepository = NULL;
public function injectMailAgentRepository(\Name\SampleExtension\Domain\Repository\MailAgentRepository $mailAgentRepository) {
$this->mailAgentRepository = $mailAgentRepository;
}
public function execute() {
$allCustomers = $this->mailAgentRepository->findAll();
DebuggerUtility::var_dump($allCustomers);exit;
// OR
$arguments = $this->request->getArguments();
$uid = $arguments['uid'];
$singleCustomer = $this->mailAgentRepository->findByUid(intval($uid));
DebuggerUtility::var_dump($singleCustomer);exit;
/*foreach ($allCustomers as $customer) {
var_dump($customer);
}*/
return true;
}
}
?>
I was missing the TCA file for the table. After adding it and declaring all the columns in there, the extbase domain object variables got filled.

phpunit: How do I pass values between tests?

I'm really running into a brick wall with this. How do you pass class values between tests in phpunit?
Test 1 -> sets value,
Test 2 -> reads value
Here is my code:
class JsonRpcBitcoinTest extends PHPUnit_Framework_TestCase
{
public function setUp(){
global $configRpcUser, $configRpcPass, $configRpcHost, $configRpcPort;
$this->bitcoindConn = new JsonRpcBitcoin($configRpcUser, $configRpcPass, $configRpcHost, $configRpcPort);
$this->blockHash = '';
}
/**
* #depends testCanAuthenticateToBitcoindWithGoodCred
*/
public function testCmdGetBlockHash()
{
$result = (array)json_decode($this->bitcoindConn->getblockhash(20));
$this->blockHash = $result['result'];
$this->assertNotNull($result['result']);
}
/**
* #depends testCmdGetBlockHash
*/
public function testCmdGetBlock()
{
$result = (array)json_decode($this->bitcoindConn->getblock($this->blockHash));
$this->assertEquals($result['error'], $this->blockHash);
}
}
testCmdGetBlock() is not getting the value of $this->blockHash that should be set in testCmdGetBlockHash().
Help in understanding what is wrong would be greatly appreciated.
The setUp() method is always called before tests, so even if you set up a dependency between two tests, any variables set in setUp() will be overwritten. The way PHPUnit data passing works is from the return value of one test to the parameter of the other:
class JsonRpcBitcoinTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
global $configRpcUser, $configRpcPass, $configRpcHost, $configRpcPort;
$this->bitcoindConn = new JsonRpcBitcoin($configRpcUser, $configRpcPass, $configRpcHost, $configRpcPort);
$this->blockHash = '';
}
public function testCmdGetBlockHash()
{
$result = (array)json_decode($this->bitcoindConn->getblockhash(20));
$this->assertNotNull($result['result']);
return $result['result']; // the block hash
}
/**
* #depends testCmdGetBlockHash
*/
public function testCmdGetBlock($blockHash) // return value from above method
{
$result = (array)json_decode($this->bitcoindConn->getblock($blockHash));
$this->assertEquals($result['error'], $blockHash);
}
}
So if you need to save more state between tests, return more data in that method. I would guess that the reason PHPUnit makes this annoying is to discourage dependent tests.
See the official documentation for details.
You can use a static variable within a function...
PHP annoyingly shares static variables of class methods with all the instances... But in this cas it can help :p
protected function &getSharedVar()
{
static $value = null;
return $value;
}
...
public function testTest1()
{
$value = &$this->getSharedVar();
$value = 'Hello Test 2';
}
public function testTest2()
{
$value = &$this->getSharedVar();
// $value should be ok
}
NB: this is NOT the good way but it helps if you need some data in all your tests...
Another option is to use static variables.
Here is an example (for Symfony 4 functional tests):
namespace App\Tests\Controller\Api;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;
use Symfony\Component\HttpFoundation\AcceptHeader;
class BasicApiTest extends WebTestCase
{
// This trait provided by HautelookAliceBundle will take care of refreshing the database content to a known state before each test
use RefreshDatabaseTrait;
private $client = null;
/**
* #var string
*/
private const APP_TOKEN = 'token-for-tests';
/**
* #var string
*/
private static $app_user__email = 'tester+api+01#localhost';
/**
* #var string
*/
private static $app_user__pass = 'tester+app+01+password';
/**
* #var null|string
*/
private static $app_user__access_token = null;
public function test__Authentication__Login()
{
$this->client->request(
Request::METHOD_POST,
'/api/login',
[],
[],
[
'CONTENT_TYPE' => 'application/json',
'HTTP_App-Token' => self::APP_TOKEN
],
'{"user":"'.static::$app_user__email.'","pass":"'.static::$app_user__pass.'"}'
);
$response = $this->client->getResponse();
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
$content_type = AcceptHeader::fromString($response->headers->get('Content-Type'));
$this->assertTrue($content_type->has('application/json'));
$responseData = json_decode($response->getContent(), true);
$this->assertArrayHasKey('token', $responseData);
$this->static = static::$app_user__access_token = $responseData['token'];
}
/**
* #depends test__Authentication__Login
*/
public function test__SomeOtherTest()
{
$this->client->request(
Request::METHOD_GET,
'/api/some_endpoint',
[],
[],
[
'CONTENT_TYPE' => 'application/json',
'HTTP_App-Token' => self::APP_TOKEN,
'HTTP_Authorization' => 'Bearer ' . static::$app_user__access_token
],
'{"user":"'.static::$app_user__email.'","pass":"'.static::$app_user__pass.'"}'
);
$response = $this->client->getResponse();
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
$content_type = AcceptHeader::fromString($response->headers->get('Content-Type'));
$this->assertTrue($content_type->has('application/json'));
//...
}
}
Another (simpler) example using static variables as pointed out by Boštjan Biber:
class ClientTest extends \PHPUnit\Framework\TestCase
{
protected $client;
protected static $testClient;
// Before a test method is run, a template method called setUp() is invoked.
public function setUp() :void
{
$this->client = new \Application\models\Clients;
}
public function testInsertCustomer()
{
$testclient = array(
'name' => 'Test Client',
'responsible' => 'Responsible Test',
'payment' => 'Test payment',
'email' => 'Test Email',
'phone' => '123-456-789'
);
$this->assertTrue($this->customer->insertCustomer($CustomerTest));
}
public function testGetCustomers()
{
$this->assertIsArray($this->customer->getCustomers());
$this->assertNotEmpty($this->customer->getCustomers());
// Save test client for other methods
$clients = $this->client->getClients();
static::$testCustomer = end($customers);
}
public function testGetClient()
{
$this->assertIsArray($this->customer->getCustomer(static::$customerTest['customer_id']));
$this->assertNotEmpty($this->customer->getCustomer(static::$customerTest['customer_id']));
}
}
You can use a static variable using the method setUpBeforeClass:
protected static $sharedId;
public static function setUpBeforeClass(): void
{
self::$sharedId = random_int(100,10000);
}
And access it in you tests like this:
public function testCreateLocation() {
echo 'Shared variable = ' . self::$sharedId;
// Use the variable in your test code and asserts...
}
/The Schwartz
This worked for me perfectly fine across all tests: $this->varablename
class SignupTest extends TestCase
{
private $testemail = "registerunittest#company.com";
private $testpassword = "Mypassword";
public $testcustomerid = 123;
private $testcountrycode = "+1";
private $testphone = "5005550000";
public function setUp(): void
{
parent::setUp();
}
public function tearDown(): void
{
parent::tearDown();
}
public function testSignup()
{
$this->assertEquals("5005550000", $this->testphone;
}
}

yii2 losing user identity after login redirect

i have looked at the other similar questions, and while this one (Yii2 user identity loss after page redirection) asks pretty much the same question, there is no solution that applies to my situation.
i have created a new identity class, i have implemented all the necessary methods and implemented the IdentityInterface. note that it does NOT extend ActiveRecord, but rather extends my own base Model class that does not derive from AR.
everything seems to work fine, i can log in and be correctly authenticated. i have traced the code and i can see that my identity class is correctly set in Yii::$app->user after IdentityInterface::validatePassword() and User::login() have been called.
however, once the login succeeds and the user is redirected, Yii::$app->user contains an empty IdentityInterface, rather than the one that was there immediately prior to the redirect.
in SiteController::actionLogin(), i have modified the code from:
return $this->goHome();
to:
$tmp = $this->goHome();
// echo '<pre>';var_dump(Yii::$app->user);echo '</pre>';exit;
return($tmp);
and i can see that Yii::$app->user still has the correct identity up until the return() statement.
can anyone tell me why i am losing my identity? i have traced through everything i can think of: yii\web\Controller, yii\base\Controller, yii\web\Response, SiteController, yii\web\User, etc...
any help at all would be greatly appreciated. thanks!
Same problem, after 3 days find solution and I it working.
My User model is:
namespace app\models;
use Yii;
class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface
{
public $username;
/**
* #inheritdoc
*/
public static function tableName()
{
return 'tbl_users';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['name', 'email', 'password'], 'required'],
[['email'], 'unique'],
[['role', 'status'], 'integer'],
[['created', 'last_update'], 'safe'],
[['name', 'email', 'password'], 'string', 'max' => 250]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Name',
'email' => 'Email',
'password' => 'Password',
'role' => 'Role',
'status' => 'Status',
'created' => 'Created',
'last_update' => 'Last Update',
];
}
public function getAuthKey() {
}
public function getId() {
return $this->id;
}
public function validateAuthKey($authKey) {
}
public static function findIdentity($id) {
}
public static function findIdentityByAccessToken($token, $type = null) {
}
public static function findByEmail($email)
{
return static::findOne(array('email'=>$email));
}
public function validatePassword($password)
{
return $this->password === $password;
}
}
I change:
public static function findIdentity($id) {
}
to:
public static function findIdentity($id) {
return self::findOne(array('id'=>$id));
}
It working for me.
I had the same problem. I had my custom class implementing yii\web\IdentityInterface. I made sure that session was enabled and enableAutologin was also true, but I had no luck at all.
Finally, I realized that in config/web.php there's a setting 'user' => [ 'identityClass' => 'app\models\User', 'enableAutoLogin' => true]
Of course, the identityClass is the default in a basic yii application. After setting this value to my custom class, identity was finally persisted.
try like this
implement implements \yii\web\IdentityInterface for your Active
record and Implement all method from \yii\web\IdentityInterface.
declare $users as static variable as private static $users = []; in your class.
Alter findByUsername() function for Get user details form Username.
In Config file add
'user' => ['identityClass' => 'app\models\active record class',
'enableAutoLogin' => true,
],
class User extends \yii\db\ActiveRecord
implements\yii\web\IdentityInterface {
private $_user = false;
public $rememberMe = true;
/*
* static variable
*/
private static $users = [];
/**
* #inheritdoc
*/
public static function tableName() {
return 'user';
}
/**
* #inheritdoc
*/
public function rules() {
return [
[['username', 'email', 'password', 'loginType'], 'required'],
];
}
/**
* #inheritdoc
*/
public function attributeLabels() {
return [
'id' => Yii::t('app', 'ID'),
'username' => Yii::t('app', 'Username'),
'email' => Yii::t('app', 'Email'),
'password' => Yii::t('app', 'Password'),
];
}
/**
* Logs in a user using the provided username and password.
* #return boolean whether the user is logged in successfully
*/
public function login() {
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
} else {
return false;
}
}
/**
* Finds user by [[username]]
*
* #return User|null
*/
public function getUser() {
if ($this->_user === false) {
$this->_user = self::findByUsername($this->username);
}
return $this->_user;
}
public function validatePassword($password) {
if ($this->password == md5($password)) {
return true;
}
return false;
}
public static function findIdentity($id) {
return static::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null) {
return static::findOne(['access_token' => $token]);
}
public function getId() {
return $this->id;
}
public function getAuthKey() {
return $this->authkey;
}
public function validateAuthKey($authKey) {
return $this->authkey === $authKey;
}
public static function findByUsername($username) {
/*
* Get Record from Usertable
*/
$user = User::findOne(["username" => $username]);
if (!empty($user)) {
/* Create array with your active record like below */
$identity_use = ['id' => $user['id'],
'username' => $user['username'],
'password' => $user['password'],
'authKey' => '',
'accessToken' =>'',];
return new static($identity_use);
}
return null;
}
}
Another simple mistake that could result in session loss would be calling
$this->redirect(...);
instead of
return $this->redirect(...);
As Yii does not call die() or exit() in this method and the code on the lines following your redirect will be executed. Being used to CodeIgniter, I had assumed this and it took me days to figure it out.
I hope this can help you
<?php
namespace app\models;
use Yii;
class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface {
private $_notification;
public static function tableName()
{
return 'users';
}
public function setNotification($n) {
Yii::$app->session['user_' .$this->id . '_notification'] = $n;
}
public function getNotification() {
$n = Yii::$app->session['user_' .$this->id . '_notification'];
Yii::$app->session['user_' .$this->id . '_notification'] = NULL;
return $n;
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['email', 'password', 'first_name'], 'required'],
[['role'], 'integer'],
[['email', 'first_name'], 'string', 'max' => 128],
[['password'], 'string', 'max' => 32]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'email' => 'E-mail',
'password' => 'Пароль',
'first_name' => 'Имя',
'role' => 'Роль',
];
}
public static function findByEmail($email) {
return self::find()->where(['email' => $email])->one();
}
public function validatePassword($password) {
if ($this->password == md5($password)) {
return true;
}
return false;
}
public static function findIdentity($id)
{
return static::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
public function getId()
{
return $this->id;
}
public function getAuthKey()
{
return $this->authkey;
}
public function validateAuthKey($authKey)
{
return $this->authkey === $authKey;
}
}

ZF2 (2.1 method) Populating select/drop down element in form

I used Zend Framework 2.1(not 2.0x) method to populate a select/drop down that is described in following links:
http://zf2.readthedocs.org/en/develop/modules/zend.form.advanced-use-of-forms.html#handling-dependencies
http://www.michaelgallego.fr/blog/2012/11/09/discover-whats-coming-for-zendform-in-zf-2-1/
Though it seems I have done as they told I got a error message like:
*... ::__construct() must be an instance of Zend\Db\TableGateway\TableGateway, none given, called in ...*
which seems service locator is not used properly.
My form code that adds my FieldSet SupplierFieldset:
namespace Inventory\Form;
use Zend\Form\Form;
use Inventory\Model;
class ItemForm extends Form
{
public function init()
{
$this->add(array(
'name' => 'sup_code',
'type' => 'Inventory\Form\SupplierFieldset'
));
}
}
My 'SupplierFieldset' class:
namespace Inventory\Form;
use Inventory\Model;
use Zend\Form\Element;
use Zend\Form\Fieldset;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\InputFilter\InputFilterProviderInterface;
use Inventory\Model\SupplierTable;
use Inventory\Model\Supplier;
class SupplierFieldset extends Fieldset implements ServiceLocatorAwareInterface
{
protected $serviceLocator;
protected $supplierTable;
public function init()
{
parent::__construct('Suppliers Code');
$this->setLabel('Supplier Code');
$this->setName('supplier_code');
$suppliers = $this->getSupplierTable()->fetchAll();
$select = new Element\Select('supplier_code');
$options = array();
foreach ($suppliers as $supplier) {
$options[$supplier->id] = $supplier->sup_code;
}
$select->setValueOptions($options);
}
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
public function getSupplierTable()
{
if (!$this->supplierTable) {
$sm = $this->getServiceLocator();
$this->supplierTable = $sm->get('Inventory\Model\SupplierTable');
}
return $this->supplierTable;
}
}
My Module.php getFormElementConfig() function:
public function getFormElementConfig()
{
return array(
'factories' => array(
'SupplierFieldset' => function($sm) {
$serviceLocator = $sm->getServiceLocator();
$supplierTable = $serviceLocator->get('Inventory\Model\SupplierTable');
$fieldset = new SupplierFieldset($supplierTable);
return $fieldset;
}
)
);
}
My SupplierTable.php model:
namespace Inventory\Model;
use Zend\Db\TableGateway\TableGateway;
class SupplierTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
}
I know SupplierTable model's constructor needs a TableGateway $tableGateway parameter. But this model is working properly when called from SupplierController.

How to pass params from controller to Zend_Form?

I know this question is already answered here. But this doesnt work for me.
The Form is generated by using the PluginLoader:
$formClass = Zend_Registry::get('formloader')->load('Payment');
$form = new $formClass(array('someval' => $my_arr));
Payment.php:
class Form_Payment extends Zend_Form
{
protected $_someval = array();
public function init()
{
$this->setAction('payment/save');
//....
$this->addElement('multiCheckbox', 'store_id', array('label' => 'Someval:', 'required' => true, 'multiOptions' => $this->getSomeval()))
}
public function setSomeval($someval) {
$this->_someval = $someval;
}
public function getSomeval() {
return $this->_someval;
}
}
As I can see the load method only returns the class name, so new $formClass(); is equal new Form_Payment() but why this isn't accept params?
Ok I found a way by myself. I was looking for a way to inject some params while my Zend_Form was initialised. It seems the only way for this is to pass the params to the constructor - which is executed before the init method.
class Form_Payment extends Zend_Form
{
private $_someval;
public function __construct(array $params = array())
{
$this->_someval = $params['someval'];
parent::__construct();
}
public function init()
{
$this->setAction('payment/save');
//....
$this->addElement('multiCheckbox', 'store_id',
array('label' => 'Someval:',
'required' => true,
'multiOptions' => $this->_someval // passed params now available
))
}
}
You can add custom function to your form class like
class Form_Payment extends Zend_Form
{
public function init()
{
$this->setAction('payment/save');
// and so on
}
public function doSome()
{
$this->setAction('other/action');
}
}
and call it after instanciating form in controller
$form = new $formClass();
$form->doSome();