I am working with Yii2 and till date using public property for non db columns like following :
public $category_id;
public function rules() {
return [
[['category_id'], 'safe'],
];
}
//// inside $dataProvider
$this->load($params);
it works perfectly. but now I want to make category_id as private so how to manage it inside rules and how to load and also set inside form element on load ?
You may use accessor and mutator for access to your private attribute, for example:
private category_id;
public function setCategory (value)
{
$this->category_id = value;
}
public function getCategory()
{
return $this->category_id;
}
These methods allow to use private attribute just as public attribute with different name in other parts of application. For example, you may use it in rules
public function rules()
{
return [['category', 'safe']];
}
Or in another code:
$model->category = 777
Related
Problem: We are upgrading from a legacy system, so solutions are constrained. I am trying to route to an unauthorized controller if a specific query string is present. If it is not present, the user is routed to the authorized controller. This is on ASP.Net Core 2.1.
Is it possible to set the controller to route based on query string? I've tried
[/home/[action]?query={query}] -> Leads to runtime error due to '?'
[/home/[action]/{query}] - > maps to /home/index/1 (not what I need)
Thanks for any help!
Edit: Alternatively, is it possible to have a separate controller Action that depends on the query parameter?
public IActionResult Index(){}
public IActionResult Index([FromQuery]string query){}
Routing doesn't seem to distinguish between these two.
You can use IActionConstraint and IParameterModelConvention interfaces for that. In short, create an IActionConstraint like this:
public class RequiredFromQueryActionConstraint : IActionConstraint
{
private readonly string _parameter;
public RequiredFromQueryActionConstraint(string parameter)
{
_parameter = parameter;
}
public int Order => 999;
public bool Accept(ActionConstraintContext context)
{
if (!context.RouteContext.HttpContext.Request.Query.ContainsKey(_parameter))
{
return false;
}
return true;
}
}
If a matching parameter is not found on the request's query string, then it will return false from the Accept method.
Than create RequiredFromQueryAttribute class like this:
public class RequiredFromQueryAttribute : FromQueryAttribute, IParameterModelConvention
{
public void Apply(ParameterModel parameter)
{
if (parameter.Action.Selectors != null && parameter.Action.Selectors.Any())
{
parameter.Action.Selectors.Last().ActionConstraints.Add(new RequiredFromQueryActionConstraint(parameter.BindingInfo?.BinderModelName ?? parameter.ParameterName));
}
}
}
Than you could decorate your mandatory query string parameters with this attribute:
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet("{id}")]
public string Get(int id, [RequiredFromQuery]string foo, [RequiredFromQuery]string bar)
{
return id + " " + foo + " " + bar;
}
}
From now than, only the following URL GET api/values/5?foo=a&bar=b would lead into the action above, all other combinations of parameters would result in response with status 404, which you can eventually replace with what you want.
You can find more info at this link https://www.strathweb.com/2016/09/required-query-string-parameters-in-asp-net-core-mvc/
i have defined a variable as an array in my model and i have defined rule for that array as :
public $nameList;
public function rules()
{
array('nameList','type'=>'array','allowEmpty'=>false),
}
I have tried this.I am getting problem?
Try this and it will work
public function rules()
{
array('nameList','type','type'=>'array','allowEmpty'=>false)
}
Let's say that I had the following API set up:
Controller:
<?php
namespace app\modules\v1\controllers;
use yii;
class ResourceController extends \yii\rest\ActiveController
{
public $modelClass = 'app\modules\v1\models\Resource';
}
Model:
use yii;
class Resource extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'ResourceTable';
}
public function fields()
{
return [
'id' => 'ResourceID',
'title' => 'ResourceTitle',
];
}
}
where my table only has the two columns, ResourceID and Title.
When I try a GET request on the API, it works fine and returns the list of resources (or single resource in the case of resource/{id}) with the aliased field names. But when I try to POST to create a resource, I want to use the aliased field names (e.g. title instead of ResourceTitle). The problem is that the default CreateAction supplied by Yii does $model->load(), which looks for the field names in the table. If I use the aliased names then it returns an error. If I use the table field names, it works fine.
So my question is, is there a way to expose resource attributes to the end user where the field names (using the fields() function) are the same for reading and creating? If possible, I'd like to avoid writing my own CreateAction.
It's necessary to add rules for new virtual properties, if you want to $model-load() save parameters to them
class OrganizationBranch extends BaseOrganization{
public function rules()
{
return array_replace_recursive(parent::rules(),
[
[['organizationId', 'cityId'], 'safe'],
]);
}
public function fields() {
return ['id',
'cityId' => 'city_id',
'organizationId' => 'organization_id',
'address',
'phoneNumbers' => 'phone_numbers',
'schedule',
'latitude',
'longitude',
];
}
public function extraFields() {
return ['branchType', 'city'];
}
public function getOrganizationId() {
return $this->organization_id;
}
public function setOrganizationId($val) {
$this->organization_id = $val;
}
public function getCityId() {
return $this->city_id;
}
public function setCityId($val) {
$this->city_id = $val;
}
}
You can create getters/setters for alias.
public function getTitle(){ return $this->ResourceTitle; }
public function setTitle($val){ $this->ResourceTitle = $val ; }
I am working on limiting access depending on user roles.
I want to be able to somehow override a belongsToMany relation to return all, if user->isAdmin() returns true.
Currently have as the AccountController index method:
public function index()
{
if(Auth::user()->isAdmin()) // can this go in beforeFilter?
return Account::all();
else
return Auth::user()->accounts;
}
in my User model:
public function accounts()
{
return $this->belongsToMany("Account");
}
Is there a neat way to do this without needing an if statement in the controller functions?
You cannot do this.
The relation method must return an instance of Relation, otherwise it throws an error.
There's nothing stopping you from creating a separate method for this:
AccountController.php:
public function index()
{
return Auth::user()->userAccounts();
}
User.php:
public function accounts()
{
return $this->belongsToMany("Account");
}
public function userAccounts()
{
if ($this->isAdmin()) return Account::all();
return $this->accounts;
}
I'm working with a server-based authentication, so I'm attempting to implement a custom login system in Yii. To learn the system, I tried to create a dummy authentication class that would automatically log in a user. I included the class in the config, but I can't figure out how to log users in.
Is there a way to automatically log in on the first use of the application (eg as a session is created?) Or is there some better way of achieving this?
The base of this is a custom authentication class:
class MyAuthentication
extends CApplicationComponent
implements IUserIdentity {
private $_username = '';
private $_authenticated = False;
...
public function authenticate()
{
$this->_username = 'exampleUser';
$this->_authenticated = True;
return True;
}
public function getIsAuthenticated()
{
return $this->_authenticated;
}
seems like you're close. something like this should work re your example:
class UserIdentity extends CUserIdentity
{
private $_username = '';
private $_authenticated = FALSE;
public function authenticate()
{
$this->_username = 'exampleUser';
$this->_authenticated = TRUE;
return $this->_authenticated;
}
public function getIsAuthenticated()
{
return $this->_authenticated;
}
}
Create a filter for Controller and check the user was authenticated or not. If not, authenticate a user.
Since my authentication was based on a server-side variable, I was able to use the expression feature of the accessRules array to check if that variable was true. I wrote a custom class to help:
class User
{
public function is_authenticated()
{
return True;
}
}
And updated my rules to use an expression check instead of a user check, as described by the documentation:
public function accessRules()
{
return array(
array('allow',
'actions'=>array('index','view', 'new'),
'expression'=>'User::is_authenticated()',
...