Yii2 missing required parameter in a constructor - yii2

I've created a new XmlResponseFormatter and now I want to change the rootTag.
class newXmlResponseFormatter extends XmlResponseFormatter
{
/**
* #var string the name of the root element.
*
*/
public $rootTag;
public function __construct($rootTag) {
parent::__construct();
$this->rootTag = $rootTag;
}
}
From a controller I set that value:
$xmlFormater = new newXmlResponseFormatter('newRootTag');
In the controller that value is available, and it sets in $rootTag but it threw the following exception:
exception 'yii\base\InvalidConfigException' with message 'Missing required parameter "rootTag" when instantiating "app\components\override\newXmlResponseFormatter".' in /var/www/html/Admin/vendor/yiisoft/yii2/di/Container.php:451
Does anyone know what can be a problem?
Thanks in advance!

First parameter in XmlResponseFormatter is $config, because XmlResponseFormatter extends Object class. You are violated liskov substitution principle.
You should rewrite your constructor like this:
class newXmlResponseFormatter extends XmlResponseFormatter
{
/**
* #var string the name of the root element.
*
*/
public $rootTag;
/**
* newXmlResponseFormatter constructor.
*
* #param string $rootTag
* #param array $config
*/
public function __construct($rootTag, $config = [])
{
$this->rootTag = $rootTag;
parent::__construct($config);
}
}
In yii2 you should call parent constructor after your code, and call parent init before your code.
$config need for simple configure model like this:
new newXmlResponseFormatter(['rootTag' => 'newRootTag']);

Related

Trying to get property of non-object ErrorException (E_NOTICE)

I am trying to isert data in mysql using laravel, while I am getting the error ErrorException (E_NOTICE)
Trying to get property of non-object, where is the problem I dont know please help me.
my controller code is PublicationController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\publication;
use Auth;
class PublicationController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//
return view('publications');
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
publications::create([
'user_id' => Auth::user()->id,
'title' => request('title'),
'status' => request('status'),
'year' => request('research_area')
]);
return 'inserted';
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
While model code is given publication.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class publication extends Model
{
//
protected $fillable = ['title','status','year'];
}
The code of my route is given.
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Route::get('education', 'EducationController#index');
Route::post('edu', 'EducationController#store');
Route::get('publications','PublicationController#index');
Route::post('pub','PublicationController#store');
The error is given Class ErrorException (E_NOTICE)
Trying to get property of non-object please help if any one know where is the problem
Consider placing PublicationController behind authentication middleware:
class PublicationController extends Controller
{
...
public function __construct()
{
$this->middleware('auth');
}
...
}
You can also use route groups:
Route::middleware(['auth'])->group(function () {
// your routes
});
If Auth::user() is null then Auth::user()->id will give you the exception you mentioned. Placing the routes or controller behind the middleware should solve this.
Edit
This assumes you are using Laravel 5.6 https://laravel.com/docs/5.6. This should work for 5.5 and 5.7.
Finally I found the answer of my question by just including 'user_id' in my model fillable arry and the above code works properly.
İ think you are not logged in so you get error when you try to get Auth::user()-id
Add this contractor to your class i think it should work for you
public function __construct(){
$this->middleware('auth');
}

PhpStorm no autocomplete when using getInstance method of a Class

Can somebody tell me why the autocompletion doesn't work when I'm using a getInstance() method instead of new ClassName?
Following is the getInstance() method of the class:
// Define The Namespace For Our Library
namespace JUnstoppable;
class JUnstoppable
{
// Instance Of The Class
protected static $instance = array ();
public static function getInstance ($forPlatformName = 'joomla')
{
$forPlatformName = strtolower($forPlatformName);
if (!isset(static::$instance[$forPlatformName]))
{
static::$instance[$forPlatformName] = new \JUnstoppable\JUnstoppable($forPlatformName);
}
return static::$instance[$forPlatformName];
}
public function __construct ($platformName = 'joomla')
{
}
public function doExecute ($test = 'lalala')
{
return $test;
}
}
Can somebody tell me why the autocompletion doesn't work when I'm using a getInstance() method instead of new ClassName?
That's because IDE does not know what can be inside your $instance static property and therefore it cannot figure out what getInstance() returns. From IDE point of view it's just plain array (elements of any types) and not an array of JUnstoppable instances.
You can place caret on $test and invoke View | Quick Documentation to see what IDE knows about that variable. If it does not say JUnstoppable there then no wonders.
Just add proper type hint for return value of getInstance() method via PHPDoc's #return tag:
/**
* My super method.
*
* #param string $forPlatformName Optional parameter description
* #return JUnstoppable
*/
public static function getInstance ($forPlatformName = 'joomla')
You can specify concrete class (JUnstoppable in this case) .. or static if this method will be used by child classes as well and they will return different instances.
Alternatively (or better say: in addition) you can typehint $instance property which IDE will use to figure out what getInstance() method returns:
/** #var JUnstoppable[] Instance Of The Class */
protected static $instance = array ();

Validating JSON input Laravel

I am using laravel , and json input from the client. I would like to know if there is a way to create a form request that does json validation instead of url parameters. I found this class online :
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class JsonRequest extends FormRequest {
/**
* Get the validator instance for the request.
*
* #return \Illuminate\Validation\Validator
*/
protected function getValidatorInstance()
{
$factory = $this->container->make('Illuminate\Validation\Factory');
if (method_exists($this, 'validator'))
{
return $this->container->call([$this, 'validator'], compact('factory'));
}
return $factory->make(
$this->json()->all(), $this->container->call([$this, 'rules']), $this->messages(), $this->attributes()
);
}
}
Now , when I make a class that extends this instead of Request, I am able to validate. This is an example:
<?php
namespace App\Http\Requests;
use App\Http\Middleware\AuthTokenMiddleware;
use App\Http\Requests\Request;
use Illuminate\Support\Facades\Input;
class VotesCreateRequest extends JsonRequest
{
public function response(array $errors)
{
//
return response()->json(["error_list" => $errors], 200);
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{return true;
if(AuthTokenMiddleware::getUser()->can('access-group',Input::get("grp_id"))){
return true;
}
else{
return false;
}
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'sub_items'=>'required|array',
'sub_items.*.email' =>'required'
];
}
}
But I want to know how to validate items inside items of the json file .
For example, i have :
{"sub_items":["something","another thing","yet another","another ","last"]}
How do I validate if all these items in sub sub_items are of type email ?

How to Extend Yii2-user dektrium profile model to be able to adding more fields

I need to override the default Profile model. I have managed to add the fields i need but there is something i am missing since. On insert and update these fields are not getting update to the database.
I have created the necessary migrations so i have these fields in the database already
What am i missing> see below my app/models/Profile.php
<?php
namespace app\models;
/**
* Description Profile
*
* This form #overrides dektrium\user\models\Profile
*/
use dektrium\user\models\Profile as BaseProfile;
use yii\web\UploadedFile;
use Yii;
use dektrium\user\models\User;
class Profile extends BaseProfile {
/**
* public variables to be added to the model
*/
public $profile_pic;
public $expertise_id;
public $country_id;
public function rules() {
$rules = parent::rules();
$rules['profile_pic'] = ['profile_pic', 'file'];
$rules['expertise_id'] = ['expertise_id', 'integer'];
$rules['country_id'] = ['country_id', 'integer'];
return $rules;
}
/**
* #inheritdoc
*/
public function attributeLabels() {
$labels = parent::attributeLabels();
$labels['profile_pic'] = \Yii::t('user', 'Profile Picture');
$labels['bio'] = \Yii::t('user', 'Biography');
$labels['expertise_id'] = \Yii::t('user', 'Expertise');
$labels['country_id'] = \Yii::t('user', 'Country');
return $labels;
}
}
First thing, remove this lines:
public $profile_pic;
public $expertise_id;
public $country_id;
If you already added those fields in the table, you dont need to declare them. As you can see, none of the others properties are being declared either. This is already being done by extending the model from ActiveRecord and declaring the tableName

symfony2: JMSSerializerBundle changes the attribute name from "className" to "class_name"

I'm using the JMSSerializerBundle to serialize my entity.
but I have the following problem: the attribute name is "className" but in my Json object I get a "class_name".
this is my entity:
/**
* Events
*
* #ORM\Table()
* #ORM\Entity
*/
class Events
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
/**
* #var string
*
* #ORM\Column(name="className", type="string", length=255)
*/
private $className;
/**
* Set className
*
* #param string $className
* #return Events
*/
public function setClassName($className)
{
$this->className = $className;
return $this;
}
/**
* Get className
*
* #return string
*/
public function getClassName()
{
return $this->className;
}
...
}
this is my controller
class myController extends Controller{
public function loadAction($action){
$request=$this->get('request');
if($request->isXmlHttpRequest())
{
switch( $action ) {
case 'load':
$resultat=$this->getDoctrine()->getManager()->getRepository('ECMUserBundle:Events')
->findAll();
$serializer = $this->get('jms_serializer');
$resultat=$serializer->serialize($resultat, 'json');
echo $resultat;
exit();
break;
...
and this my Json
[{"id":90,"title":"holliday","start":"2014-03-25T01:00:00+0000","end":"2014-03-25T01:00:00+0000","class_name":"label-orange","allday":"true"}]
is this the logical behaviors?
As #mike said, you can use #SerializedName annotation to change serialized property name to arbitrary string.
Also, if you want to change naming strategy on application level. You can use the following workaround:
config.yml
parameters:
jms_serializer.serialized_name_annotation_strategy.class: JMS\Serializer\Naming\IdenticalPropertyNamingStrategy
Also, check this issue.
Check the documentation for the #SerializedName annotation:
http://jmsyst.com/libs/serializer/master/reference/annotations
#SerializedName:
This annotation can be defined on a property to define the serialized name for a property. If this is not defined, the property will be translated from camel-case to a lower-cased underscored name, e.g. camelCase -> camel_case.
If you just want to use the camel case version once, without annotations, use the IdenticalPropertyNamingStrategy:
$serializer = SerializerBuilder::create()->setPropertyNamingStrategy(new IdenticalPropertyNamingStrategy())->build();
Inside Symfony, it make way more sense to use a compiler pass, as it avoid losing the #SerializedName annotation.
<?php
namespace AppBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class JMSSerializerCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$container->getDefinition('jms_serializer.serialized_name_annotation_strategy')
->replaceArgument(0, new Reference('jms_serializer.identical_property_naming_strategy'));
}
}