How can I get get params in url via slashes in Yii2? - php

I want to build url with get params via slashes.
For exapmle, I want this code:
Url::to(['/controller/action',
'filter' => 'filter,
'param1' => 'value1',
'param2' => 'value2' ...]);
to generate url:
//path.to.site/controller/action/filter/param1/value1/param2/value2...
Is there a way to make this via defaut urlManager?

Sure:
'urlManager' => [
'rules' => [
'<controller>/<action>/<filter>/param1/<param1>/param2/<param2>' => '<controller>/<action>',
],
],
Then Url::to will return following result:
Url::to([
'/controller/action',
'filter' => 'some-filter',
'param1' => 'value1',
'param2' => 'value2'
]);
// Result: http://base.url/controller/action/some-filter/param1/value1/param2/value2

use Yii;
use yii\web\UrlRuleInterface;
class SearchUrlRule implements UrlRuleInterface
{
public function parseRequest($manager, $request)
{
$pathInfo = $request->getPathInfo();
if (strpos($pathInfo, 'somepath') !== 0) {
return false;
}
$parameters = explode('/', $pathInfo);
if ($parameters[1] !== 'f') {
return false;
}
$route = 'controller/action';
$params = [
'filter' => 'f'
];
$count = count($parameters);
$i = 2;
var_dump($parameters);
while (($i + 1) < $count) {
$params[$parameters[$i]] = $parameters[$i + 1];
$i = $i + 2;
}
Yii::trace("Request parsed with URL rule: action/controller", __METHOD__);
return [$route, $params];
}
public function createUrl($manager, $route, $params)
{
if ($route !== 'controller/action') {
return false;
}
if ($params['filter'] !== 'f') {
return false;
}
unset($params['filter']);
//If a parameter is defined and not empty - add it to the URL
$url = 'somepath/f/';
foreach ($params as $k => $param) {
$url .= "$k/" . $param;
}
return $url;
}
}
Here is code, that solved my problem. And in config:
'rules' => [
...
['class' => 'frontend\components\SearchUrlRule'],
...

Related

Is that possible to know if element exists inside an array without looping through the array?

I have an array of elements with the same structure each.
Here's an example :
<?php
$arr =
[
[
"el_name" => "abcd",
"el_data" => "raw_dataè_15264df156g18df",
],
[
"el_name" => "efgh",
"el_data" => "raw_data_sd25g",
],
[
"el_name" => "ijkl",
"el_data" => "raw_data_dfdfgn48",
],
[
"el_name" => "mnop",
"el_data" => "raw_data_²545",
],
];
$new_el = [
"el_name" => "efgh",
"el_data" => "raw_data_sd25g",
];
I want to add $new_el only if it's not already present in $arr. It'd be handy if php had a array_element_exists() function ;-)
For the sake of the question I tried this:
$exists = false;
foreach($arr as $el) {
$equal=true;
foreach(array_keys($el) as $key) {
if(isset($new_el[$key]) && $new_el[$key] === $el[$key]) {
null;
//equality
} else {
$equal = false;
}
}
if($equal === true) {
$exists = true;
break;
}
}
if($exists === true ) {
echo '$new_el already exists in $arr' . PHP_EOL;
} else {
echo '$new_el doesn\'t still exists in $arr' . PHP_EOL;
$arr[] = $new_el;
}
Do you think there are more efficient, 'simpler' ways ?...
You are probably looking for in_array() function.
in_array($new_el, $arr);
returns true.
function array_element_exists($new_el,$arr){
$found = array_filter($arr, function($arr) use ($new_el) {
return $arr['el_name'] === $new_el['el_name'] &&
$arr['el_data'] === $new_el['el_data'];
});
return $found;
}
$exsist = ["el_name" => "efgh","el_data" => "raw_data_sd25g"];
$notExsist = ["el_name" => "newName","el_data" => "newData",];
//will not be added since it is already exist
if (!array_element_exists($exsist,$arr)) {
$arr[] = $exsist;
}
//will be added because it is new and not exist in `$arr`
if (!array_element_exists($notExsist,$arr)) {
$arr[] = $notExsist;
}

Laravel: Add Pagination to Json Response

I have an array for showing users' contacts list to each other.
I want to add ->paginate(10) features for json response but I could not find where I must put it.
My index function:
public function index()
{
$contacts = [];
$user = request()->user();
// Loop through the contacts and format each one
Contact::for($user->id)->get()->each(function ($contact) use ($user, &$contacts) {
$friend = $contact->user1_id === $user->id ? $contact->user2 : $contact->user1;
$contacts[] = $friend->toArray() + ['room' => $contact->room->toArray()];
});
return response()->json($contacts);
}
You can create a collection for the contact and use LenfthAwarePaginator
class ContactResourceCollection extends ResourceCollection
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request
* #return array
*/
public function toArray($request)
{
$response = [
'data' => $this->collection,
];
if($this->resource instanceof LengthAwarePaginator)
{
$response['pagination'] = [
'total' => $this->resource->total(),
'lastPage' => $this->resource->lastPage(),
'perPage' => $this->resource->perPage(),
'currentPage' => $this->resource->currentPage(),
'nextPageUrl' => $this->resource->nextPageUrl(),
'previousPageUrl' => $this->resource->previousPageUrl(),
];
}
return $response;
}
}
In the controller method add this line:
return new UserResourceCollection($users);
Here is the total code
$contacts = Contact::where('user_id', $user->id)->paginate(12);
if($contacts->count()){
$pageIndex = array();
$lastPage = $contacts->lastPage();
$user = request()->user();
for($i= 2; $i<=$lastPage; $i++){
array_push($pageIndex, $i);
}
return response()->json([
'contacts' => $contacts->map(function ($contact) use ($user) {
if($contact->user1_id === $user->id){
return [
'friend' => $contact->user2,
'room' => $contact->room,
];
} else {
return [
'friend' => $contact->user1,
'room' => $contact->room,
];
}
})->toArray(),
'per_page' => $contacts->perPage(),
'on_first_page' => $contacts->onFirstPage(),
'last_page' => $contacts->lastPage(),
'first_page_url' => $contacts->url(1),
'next_page_url' => $contacts->nextPageUrl(),
'prev_page_url' => $contacts->previousPageUrl(),
'last_page_url' => $contacts->url($contacts->lastPage()),
'total' => $contacts->total(),
'pageIndexArray' => $pageIndex,
'errors' => false,
]);
} else {
// Do Nothing
}
Call
GET 'URL?page='+Page_index to get the response in JS (AJAX)
I am not sure but try : replace get() to paginate(10)
Contact::for($user->id)->paginate(10)->each(function ($contact) use ($user, &$contacts) {
$friend = $contact->user1_id === $user->id ? $contact->user2 : $contact->user1;
$contacts[] = $friend->toArray() + ['room' => $contact->room->toArray()];
});
Can you change the query into:
$contacts = Contact::for($user->id)->paginate(10);
Then after this query you can use for loop for $contact;
foreach ($contacts as $key => $contact)
{
$friend = $contact->user1_id === $user->id ? $contact->user2 : $contact->user1;
$contacts[] = $friend->toArray() + ['room' => $contact->room->toArray()];
}
Paginate first before get into loop/each.

Session Handler behaves like object

I want to force $_SESSION behave like object using custom session handler. Code as follows,
$_SESSION = [
'user' => [
'id' => '7',
'name' => 'James',
'lastname' => 'Bond',
'login' => '007',
'pass' => 'qwe7fyqw9mhev8qhr',
],
'kill' => [
'Mr_Muscle' => [
'status' => 'alive',
],
'Joe_Black' => [
'status' => 'dead',
]
],
];
$session = new Session();
echo $session->user->name;
$session->kill->Mr_muscle->status = 'dead';
$session->save();
I did it almost but I get warning:
Warning: Creating default object from empty value in /var/www/project/mvc/bootstrap.php on line 80
when I'm trying to create new value, in this case:
$session->kill->Dr_Quinn->status = 'dead';
Value will be created but I don't want to hide this warning, I want to do away with it.
class Session
{
public function __construct()
{
foreach ($_SESSION as $key => $value)
{
$this->{$key} = $value;
}
}
public function __set($name, $value)
{
$this->$name = $this->arrayToObject($value);
}
private function arrayToObject($array) {
if (!is_array($array)) {
return $array;
}
$object = new stdClass();
if (is_array($array) && count($array) > 0) {
foreach ($array as $name=>$value) {
$name = strtolower(trim($name));
if (!empty($name)) {
$object->$name = $this->arrayToObject($value);
}
}
return $object;
}
else {
return FALSE;
}
}
public function save()
{
$_SESSION = json_decode(json_encode(get_object_vars($this)), true);
}
How to fix it?
Just do
if (!isset($session->kill->Mr_muscle))
$session->kill->Mr_muscle = new stdClass();
$session->kill->Mr_muscle->status = 'dead';
to avoid this warning.

Laravel Argument 1 passed to

I'm trying to do my coding, but I ran into this issue. Thing is, I did it exactly the same like my first code, but it's working there.
ErrorException in CoinflipController.php line 115: Argument 1 passed
to App\Http\Controllers\CoinflipController::CoinflipToJson() must be
an instance of App\Models\Game\Coinflip\Coinflip, instance of
Illuminate\Database\Eloquent\Collection given, called in
C:\xampp\htdocs\site\app\Http\Controllers\CoinflipController.php on
line 104 and defined
Coinflip File
<?php
namespace App\Models\Game\Coinflip;
use Illuminate\Database\Eloquent\Model;
class Coinflip extends Model {
const STATUS_ACTIVE = 0;
const STATUS_ROLLING = 1;
const STATUS_ENDED = 2;
protected $table = 'coinflip';
protected $fillable = [
'status',
'winner_steam_id',
'winner_probability',
'winner_value',
'hash',
'ticket',
'seed',
'player1',
'player1_side',
];
protected $dates = [ 'draw_at' ];
protected $casts = [
'winner_steam_id' => 'string',
'winner_probability' => 'float',
'winner_value' => 'float',
'ticket' => 'double'
];
public function entry(){
return $this->hasMany( 'App\Models\Game\Coinflip\CoinflipEntry', 'coinflip_id' );
}
public function winner(){
return $this->hasOne( 'App\User', 'steam_id', 'winner_steam_id' );
}
public function getCommissionValue(){
$val = 0;
foreach( $this->entry as $entry ){
foreach( $entry->item as $item ){
if ( $item->status == CoinflipEntryItem::STATUS_COMMISIONED )
$val += (float)$item->price;
}
}
return $val;
}
}
CoinflipToJson Function (From 1st line is the Error)
public function CoinflipToJson( Coinflip $coinflip, $showExtra = false ){
$canDeposit1 = $coinflip->value * 0.10 + $coinflip->value;
$canDeposit2 = $coinflip->value - $coinflip->value * 0.10;
$data = [
'id' => $coinflip->id,
'hash' => $coinflip->hash,
'gameValue' => $coinflip->value,
'canDeposit1' => $canDeposit1,
'canDeposit2' => $canDeposit2,
'skinValue' => 0,
'skinCount' => 0,
'timeStart' => $coinflip->created_at->getTimestamp(),
'timeEnd' => $coinflip->draw_at ? $jackpot->draw_at->getTimestamp() : 0,
'timeEndIn' => $coinflip->draw_at ? $jackpot->draw_at->getTimestamp() - time() : -1,
'timeMax' => Setting::of('JackpotExtendTime', 15)->getValue(),
'entry' => []
];
if ( $showExtra ){
$data['winningPercentage'] = $coinflip->ticket;
$data['winnerId'] = $coinflip->winner_steam_id;
$data['secret'] = $coinflip->seed;
}
foreach( $coinflip->entry as $entry ){
$entryData = $this->entryToJson( $entry );
$data['entry'][] = $entryData;
$data['skinValue'] += $entryData['skinValue'];
$data['skinCount'] += $entryData['skinCount'];
}
return $data;
}
Code where I am calling it (Line 5)
public function current( Request $request ){
$coinflip = $this->getCurrentGame();
if($coinflip){
$data = [
'current' => $this->CoinflipToJson($coinflip)
];
return response()->json($data);
} else return response()->json(['error' => 'No Games']);
}
getCurrent Game Function
public function getCurrentGame(){
$coinflip = Coinflip::where('status', Coinflip::STATUS_ACTIVE)->get();
return $coinflip;
}
In your getCurrentGame() method, the get() method always returns a Collection, even if there was only one record. If you query will only ever return one record, you can just change get() to first(), and it will return the record instance, instead of a Collection.

Doctrine Repository accept array for getAll

In a repository, I need a custom getALL query which checks for items based on an array of data. e.g. I need to be able to send $params = [ 'type' => [ 'type1', 'type2' ], 'username' => $username ] but I can currently only send one parameter such as: $params = ['type' => 'type1', 'username' => $username].
What would be the best way of adding acceptance of an array (like the one above) to this getAll query?:
public function getAllQuery($params = [])
{
$query = $this->createQueryBuilder('c');
if(count($params))
{
foreach($params as $param => $value)
{
//todo need to make it accept an array of parameters
if(in_array($param, $this->getClassMetadata()->getFieldNames()) && $param != 'deleted')
{
$query
->andWhere(sprintf('c.%1$s LIKE :%1$s', $param))
->setParameter($param, sprintf('%%%s%%', $value));
}
/*code already exists here for checking other parameters
outside of 'type' (e.g. 'username') */
}
}
return $query->getQuery();
}
I am not able to comment so I will answer without to be sur that I've understand the question. Are you waiting something like this ? In this case it's more a PHP problem than Doctrine.
The results of the past code : here.
$params = array( 'type' => array( 'type1', 'type2' ), 'username' => 'flavien');
$requiredFields = array('type');
if(count($params))
{
foreach($params as $param => $value)
{
if(in_array($param, $requiredFields) && $param != 'deleted')
{
if(is_array($value))
{
echo "My param: {$param}" . PHP_EOL;
for($i=0; $i < count($value); $i++) {
echo $value[$i] . PHP_EOL;
}
}
}
}
}

Categories