In PhpStorm 2021.1 working with Laravel 9 I periodically use “Reformat Code” functionality with all content of the file selected.
But some methods of this file looks differently formatted :
public function setBannerId(int $value): self
{
$this->bannerId = $value;
return $this;
}
...
public
function setDescriptionSize(
int $value
): self {
$this->descriptionSize = $value;
return $this;
}
I dislike a way the second method is formatted. I want all methods to be formatted as the first method?
UPDATED :
“Reformat Code” tab https://prnt.sc/cxkkYQdcRPjd printscreen
Can it be done?
Related
I'm using the latest version of PhpStorm (2022.3.1) and Laravel 9+. This is not a huge issue, but rather a major eyesore.
For some reason when I use a Model to create a custom Attribute like this:
public function getFormattedStartDateAttribute(): string
{
if (!$this->start_date) {
return 'TBD';
} else {
return $this->start_date->format('M. d, Y');
}
}
And use in the view like this or this:
Date {{ $event->formattedStartDate }}
Date {{ $event->formatted_start_date }}
PhpStorm still says the method has no usages?
Image:
Is there a way to fix this? I've tried reindexing my project. This is a new feature called Code Vision.
The issue is very easy to solve, you can use barryvdh/laravel-ide-helper and then run php artisan ide:model, that will go over the models and create a PHPDoc block (you can add options and create them in the same model file or in a new file where you only have this PHPDock blocks), and PHPStorm will read this doc block and know when you are calling attributeWhatever is what type.
It will add this in your case:
/**
* #property string $formattedStartDate
*/
This way, any IDE that is capable of understanding PHPDock blocks, will understand that when you do $class->formattedStartDate, you are refering to that one, and it is of type string.
BUT, no IDE (unless using a plugin that I am not aware of) will understand that getFormattedStartDateAttribute -> formattedStartDate, so you will still get no usages for getFormattedStartDateAttribute, but at least you can track formattedStartDate and do whatever you want with it.
One quick tip, if you are using Laravel 9+, please change that code from:
public function getFormattedStartDateAttribute(): string
{
if (!$this->start_date) {
return 'TBD';
} else {
return $this->start_date->format('M. d, Y');
}
}
To:
public function formattedStartDate(): \Illuminate\Database\Eloquent\Casts\Attribute
{
return Attribute::get(
function ($value, $attributes) {
if (! $attributes['start_date']) {
return 'TBD';
} else {
return $attributes['start_date']->format('M. d, Y');
}
}
);
}
Why? Because using getFormattedStartDateAttribute is the old way, Laravel 9+ made it easier, read about Accessors.
See that getXXXXAttribute and setXXXXAttribute is not even present on the documentation anymore.
I'm creating a like feature for my application where users can like posts, events, products etc.
I have a LikeController and a Trait which handles the like functionality
public function store(Post $post)
{
$post->like();
return back();
}
The code above is to like a post
I don't want to duplicate code and create separate functions to perfrom the same exact thing on events or products and I was wondering how to perform route model binding and get the application to just execute the one function, passing model information depending on what is being liked post, event or product.
The following code works fine but does not implement the DRY principle
public function store(Post $post)
{
$post->like();
return back();
}
public function store_event(Event $event)
{
$event->like();
return back();
}
The followinf is the trait
trait LikeTrait
{
public function getLikesCountAtrribute()
{
return $this->likes->count();
}
public function like()
{
if (!$this->likes()->where(['user_id' => auth()->id()])->exists()) {
$this->likes()->create(['user_id' => auth()->id()]);
}
}
public function likes()
{
return $this->morphMany(Like::class, 'likeable');
}
public function isLiked()
{
return !!$this->likes->where('user_id', auth()->id())->count();
}
}
My web routes file is as follows
Route::post('post/{post}/likes', 'LikeController#store');
Route::post('event/{event}/likes', 'LikeController#store_event');
So the outcome I want is to call the same method and pass the relevant model.
Thanks in advance
You can have a specific route for such actions, may it be 'actions':
Route::post('actions/like','ActionsController#like')->name('actions.like');
Then in the request you send the object you wish to perform the action on, i personal have it hashed, the hash contains the ID and the class_name (object type) in an stdClass.
That's how i personally do it:
Every Model i have inherits Base Model, which contains hash attribute, which contains
$hash = new stdClass;
$hash->id = $this->id;
$hash->type = get_class($this);
return encrypt($hash);
This will return a string value of what's there, and encrypted, you can have a password for that as well.
Then you let's say you have the like button inside a form or javascript you can do that:
<form action="{{ route('actions.like') }} method="post">
<input type="hidden" name="item" value="{{ $thisViewItem->hash }}">
<button type="submit">Like</button>
</form>
Doing so, when liking an object you send the hashed string as the data, thus getting a request of $request->get('item') containing the object (id and type). then process it in the controller however you like.
If you're sending this through javascript you may want to urlencode that.
then in ActionsController#like you can have something like that:
$item = decrypt($request->get('item'));
# Will result in:
# Item->id = 1;
# Item->type = 'App\Post';
$Type = $Item->type;
# Build the model from variable
# Get the model by $item->id
$Model = (new $Type)->find($item->id);
# Like the model
$Like = $Model->like();
// the rest...
I personally prefer to combine and encrypt the id+type in a string, but you can send the id and type in plain text and have a route named like so:
Route::post('actions/like/{type}/{id}','ActionsController#like');
Then build the model from the Type+ID followed by what you have in trait ($Model->like());
It's all up to you, but i'm trying to hint that if you want to reuse the like action in many places, you may want to start building the logic starting from the action itself(likes, comments) not from the target (posts, events).
The codes i placed in here are written in here and not pasted from what i actually do, I'm trying to get you the concept. You can write it however you prefer.
I don't know whether this is gonna work, but please have a go.
You could try explicit binding. Lets define explicit bindings in the App\Providers\RouteServiceProvider:
public function boot()
{
parent::boot();
Route::model('post', App\Post::class);
Route::model('event', App\Event::class);
}
Then defining the routes:
Route::post('/posts/{post}/likes', 'LikesController#store');
Route::post('/events/{event}/likes', 'LikesController#store');
Finally in the controller:
class LikesController extends Controller
{
public function store($object)
{
$object->like();
}
}
I am thinking of any techniques of autoloading the view files according to url.
For example:
public function addProducts()
{
return view('admin.addProducts');
}
public function editProducts()
{
return view('admin.editProducts');
}
public function allProducts()
{
return view('admin.allProducts');
}
Here, the Controller's method name is identical to view file name. So, I am thinking, if it is possible to load the view files without writing same kind of method again and again.
Enlighten me.
If your route only needs to return a view, you may use the Route::view method.
For example:
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
read more here
It's the call PHP magic, man. https://repl.it/#Piterden/PHP-call-magic?language=php
public function __call($method, $parameters)
{
if (str_contains($method, 'Product')) {
return view("admin.{$method}");
}
}
btw, it's not a good practice for controller.
I have a Joomla helper class that I'm using for module development with a method I'm trying to call:
class modCamcloudReferralHelper
{
/*
* Sanitize email form
*/
public function isInjected($str) {
$inject = "/(\r|\t|%0A|%0D|%08|%09)+/i";
return (preg_match($inject, $str) > 0);
}
public static function sendEmail() {
$jinput = JFactory::getApplication()->input;
$email = $jinput->post->get('email', '', 'STRING');
//check email is fine
if (isInjected($email)){ //never get into this code and it causes some sort of failure
echo "blah";
}
}
}
Simple, right? But this code just gives me a blank page and I don't see any errors...anywhere. I can instead just put this code right into my sendEmail function and it works just fine:
$inject = "/(\r|\t|%0A|%0D|%08|%09)+/i";
if (preg_match($inject, $email) > 0){
echo "This works";
}
I've had this problem with my Joomla components I've built before. For some reason calling this function from inside the same class is not working. It must be a Joomla thing...or I'm going nuts. Any ideas?
You should call the method with a reference to its container, even if it's local.
So the right syntax here is:
if (self::isInjected($email))
of from another class:
modCamcloudReferralHelper::isInjected(
This is good for helpers: just make sure you declare the method you are invoking as static
public static function isInjected($str) {
If however you're calling a method on an instantiated class (a view, a template, a model, you should use
$this->method()
i have a controller having following script
class get extends CI_Controller
{
function get_password()
{
$this->load->model('fetch_model');
$user_pass=$this->fetch_model->get_password();
$data['user_pass'] = json_encode($user_pass);
echo $data['user_pass'];
}
}
and a script on view page as this
function get_password(){
$.post("<?php echo base_url();?>admin.php/get/get_password",function(data)
{
for(i=0;i<data.length;i++)
{
$('#password').val(data[i].password);
$('#username').val(data[i].username);
}
},"json");
}
now if i use the following script in model then the ajax post is working perfectly..
class fetch_model extends CI_Model
{
function get_password()
{
return $this->db->query("SELECT * FROM td_admin_user")->result_array();
}
}
but when i change the model script into this, then the ajax script isnt working
class fetch_model extends CI_Model
{
function get_password()
{
foreach($this->db->query("SELECT * FROM td_admin_user")->result() as $r_pass)
{
$pass=$r_pass->password;
$user=$r_pass->username;
}
$user_pass=array('username'=>$user,
'password'=>$pass);
return $user_pass;
}
}
but to be very frankly, i need to send data in the following way
$user_pass = array('username'=>$user, 'password'=>$pass);
and not as result_array()
so please help me in this context, thanks in advance
This is not a bug! Did you even look at what type of data is returned in each call?
In your JS, you are using:
$('#password').val(data[i].password);
Where data is an indexed array - exactly what is returned by ->result_array()
But you want it to be a key based array:
$user_pass=array('username'=>$user, 'password'=>$pass);
If that's the case, you should forget using the for loop on JS (specially if your query only results in one row) and use
$('#password').val(data.password);
Instead.
Also look at console.log (if you are using firebug/developer tools) and try print_r or var_dump on the PHP side to understand the data formats you are returning.