Getter in a Behavior cakephp 3 - cakephp

I've just created a tag behavior to manage tags in an input text field (all keywords are separate by a comma). To do that I name my input "tag_string".
So I need to use a getter to handle the string.
I didn't understand how implement a _getTagString() method directly in the behavior.
If I use my getter (getTagString) in each entities file that use my behavior all my code works fine.
So to avoid write the same getter in each file I want to put it in my behavior file. But it doesn't work.
Here is my method:
public function _getTagString() {
if (isset($this->_properties['tag_string'])) {
return $this->_properties['tag_string'];
}
if (empty($entity->tags)) {
return '';
}
$tags = new Collection($entity->tags);
$str = $tags->reduce(function ($string, $tag) {
return $string . $tag->name . ', ';
}, '');
return trim($str, ', ');
}
Thanks for your help

After several searches I didn't find anything to implement accessors directly in the behavior.
I use trait, and It works fine.

Related

unexpected result in a query in laravel

I’m a beginner in Laravel but have a problem at first. I wrote this query and I’m waiting for Sonya Bins as result but unexpectedly I see ["Sonya Bins"]. what’s the problem?
Route::get('products', function () {
$articles=DB::table('users')->where('id','2')->get()->pluck('name');
return view('products',compact('articles'));
});
pluck will return array if you want to get only single value then use value
// will return array
$articles=DB::table('users')->where('id','2')->get()->pluck('name');
//will return string
$articles=DB::table('users')->where('id','2')->value('name');
// output Sonya Bins
here is an example from the documentation:
if you don't even need an entire row, you may extract a single value from a record using the value method. This method will return the value of the column directly:
$email = DB::table('users')->where('name', 'John')->value('email');
Read more about it here
Hope it helps.
Thanks
pluck() used to return a String before Laravel 5.1, but now it returns an array.
The alternative for that behavior now is value()
Try this:
Route::get('products', function () {
$articles=DB::table('users')->where('id','2')->get()->value('name');
return view('products',compact('articles'));
});
I think it's easier to use the Model + find function + value function.
Route::get('products', function () {
$articles = User::find(2)->value('name');
return view('products',compact('articles'));
});
pluck will return the collection.
I think id is your primary key.
You can just get the first record, and call its attribute's name:
DB::table('users')->where('id','2')->first()->name;
or
DB::table('users')->find(2)->name;
First thing is that you used invalid name for what you pass to view - you don't pass articles but user name.
Second thing is that you use get method to get results instead of first (or find) - you probably expect there is only single user with id = 2.
So to sum up you should use:
$userName = DB::table('users')->find(2)->name;
return view('products',compact('userName'));
Of course above code is for case when you are 100% sure there is user with id = 2 in database. If it might happen there won't be such user, you should use construction like this:
$userName = optional(DB::table('users')->find(2))->name;
($userName will be null if there is no such record)
or
$userName = optional(DB::table('users')->find(2))->name ?? 'No user';
in case you want to use custom string.

Return Stringbuilder when using variable name to create string builder

trying to return string builder in a loop. is this workable.. I am collecting a list with each(), then appending 'it' to "scriptBldr_" to create a different object name each time to hold the string. then I collect the object names in a list. And trying to return using a for loop for each object name. But it's failing.
List.each {
String builderstring = "scriptBldr_" + it.replaceAll (/"/, '')
StringBuilder $builderstring = StringBuilder.newInstance()
if (ValidUDA == "Region") {
$builderstring <<"""
XYZCode
"""
StringBuilders.add(builderstring)
}
}
for(item in StringBuilders)
{
return item
}
I guess the following code does what you intended to code:
def myList = ['Hello "World"', 'asb"r"sd']
def ValidUDA = "Region"
def builders = [:]
myList.each {
String builderstring = "scriptBldr_" + it.replaceAll (/"/, '')
builders[builderstring] = StringBuilder.newInstance()
if (ValidUDA == "Region") {
builders[builderstring] <<"""
XYZCode
"""
}
}
return builders
A return statement will immediatly return from the method and hence will exit the loop and only called once. So, I guess, what you wanted to achieve is to return a list of StrinngBuilders.
some hints:
it is unusual in Groovy to start a variable with $ and you can run into problems with such a naming
when asking a question on SO, try to come up with a working example. As you can see, you example was missing some definitions
Update: as you've stated in you comment that you tryed to create dynamic variable names, I've updated the code to use maps. The returned map now contains the StringBuilders together with their names.

Indirect modification of overloaded element of Illuminate\Support\Collection has no effect

im quite new in laravel framework, and im from codeigniter.
I would like to add new key and value from database
static function m_get_promotion_banner(){
$query = DB::table("promotion_banner")
->select('promotion_banner_id','promotion_link','about_promotion')
->where('promotion_active','1')
->get();
if($query != null){
foreach ($query as $key => $row){
$query[$key]['promotion_image'] = URL::to('home/image/banner/'.$row['promotion_banner_id']);
}
}
return $query;
}
that code was just changed from codeigniter to laravel, since in codeigniter there are no problem in passing a new key and value in foreach statement
but when i tried it in laravel i got this following error :
Indirect modification of overloaded element of Illuminate\Support\Collection has no effect
at HandleExceptions->handleError(8, 'Indirect modification of overloaded element of Illuminate\Support\Collection has no effect', 'C:\xampp\htdocs\laravel-site\application\app\models\main\Main_home_m.php', 653, array('query' => object(Collection), 'row' => array('promotion_banner_id' => 1, 'promotion_link' => 'http://localhost/deal/home/voucher', 'about_promotion' => ''), 'key' => 0))
please guide me how to fix this
thank you (:
The result of a Laravel query will always be a Collection. To add a property to all the objects in this collection, you can use the map function.
$query = $query->map(function ($object) {
// Add the new property
$object->promotion_image = URL::to('home/image/banner/' . $object->promotion_banner_id);
// Return the new object
return $object;
});
Also, you can get and set the properties using actual object properties and not array keys. This makes the code much more readable in my opinion.
For others who needs a solution you can use jsonserialize method to modify the collection.
Such as:
$data = $data->jsonserialize();
//do your changes here now.
The problem is the get is returning a collection of stdObject
Instead of adding the new field to the result of your query, modify the model of what you are returning.
So, assuming you have a PromotionBanner.php model file in your app directory, edit it and then add these 2 blocks of code:
protected $appends = array('promotionImage');
here you just added the custom field. Now you tell the model how to fill it:
public function getPromotionImageAttribute() {
return (url('home/image/banner/'.$this->promotion_banner_id));
}
Now, you get your banners through your model:
static function m_get_promotion_banner(){
return \App\PromotionBanner::where('promotion_active','1')->get();
}
Now you can access your promotionImage propierty in your result
P.D:
In the case you are NOT using a model... Well, just create the file app\PromotionImage.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class PromotionImage extends Model
{
protected $appends = array('imageAttribute');
protected $table = 'promotion_banner';
public function getPromotionImageAttribute() {
return (url('home/image/banner/'.$this->promotion_banner_id));
}
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'promotion_banner_id','promotion_link','about_promotion','promotion_active'
];
just improving, in case you need to pass data inside the query
$url = 'home/image/banner/';
$query = $query->map(function ($object) use ($url) {
// Add the new property
$object->promotion_image = URL::to( $url . $object->promotion_banner_id);
// Return the new object
return $object;
});
I've been struggling with this all evening, and I'm still not sure what my problem is.
I've used ->get() to actually execute the query, and I've tried by ->toArray() and ->jsonserialize() on the data and it didn't fix the problem.
In the end, the work-around I found was this:
$task = Tasks::where("user_id", $userId)->first()->toArray();
$task = json_decode(json_encode($task), true);
$task["foo"] = "bar";
Using json_encode and then json_decode on it again freed it up from whatever was keeping me from editing it.
That's a hacky work-around at best, but if anyone else just needs to push past this problem and get on with their work, this might solve the problem for you.

translating the Time text to another language

How can i translate the default Cake php time helper strings in my application, i'm using in Cake php a function called timeAgoInWords which from the time helper function, it give me a text like 5 hours, 52 minutes ago .
I want to translate this to another language, how can i do that ? i searched the documentation and i didn't get anything .
<?php echo $this->Time->timeAgoInWords($question['Question']['created']) ?>
You need a customized helper to get your stuff done. timeAgoInWords helper does not give the flexiblity of replacing words with your words.
Here, create a file called TimeagoHelper.php under your View/Helper
I am not sure which language you want translation in, I will write in English, you can replace your words.
<?php
App::uses('AppHelper', 'View/Helper');
class TimeagoHelper extends AppHelper {
public function __construct(View $view, $settings = array()) {
parent::__construct($view, $settings);
}
public function timeago($datetime) {
$datetime1 = new DateTime($datetime);
$datetime2 = new DateTime('now');
$obj = $datetime1->diff($datetime2);
if($obj->days == 1) {
$time = $obj->format('%a day'); // Replace your word
} elseif($obj->days == 0) {
if($obj->h == 0) {
if($obj->i == 0) {
$time = $obj->s . ' seconds'; // Replace your word
} else {
$time = $obj->i . ' minutes'; // Replace your word
}
} else {
$time = $obj->h . ' hours'; // Replace your word
}
} else {
$time = $obj->format('%a days'); // Replace your word
}
return $time.' ago'; // Replace your word
}
}
Load this helper in your action or controller.
I have been using php 5.5 since quite sometime, am not sure if it works on lesser versions, i.e. don't remember if concat is allowed as done for seconds and minutes. Incase, it doesn't work, assign them to variables and concat those.
Use it in View's .ctp file like so:
$this->Timeago->timeago($question['Question']['created']);
PS: CakeTime comes in handy too, check out the api for possibilities.
Cheers!

CakePHP, GET Parameters and routing

I am fairly new to cakephp but I have a question relating to urls and parameters. I would like to be able to have a url that looks like a standard url e.g:
http://www.mysite.com/controller/myaction?arg=value&arg2=val
I would like that url to map to an action in my controller as follows:
function myaction($arg = null, $arg2 = null)
{
// do work
}
I realize that cakephp has routing as described here, however, honestly this seems over engineered and results in a url string that is nonstandard.
In my current situation the url is being generated and invoked by an external (billing) system that knows nothing about cake and doesn't support the cake url format.
You can have your URL in any form. It's just CakePHP allows you to retrieve the variable passed through GET from the variable $this->params['url']
function myaction()
{
if(isset($this->params['url']['arg']))
$arg = $this->params['url']['arg'];
if(isset($this->params['url']['arg2']))
$arg2 = $this->params['url']['arg2'];
}
Solution in AppController for CakePHP 2.x
class AppController extends Controller {
....
/***
* Recupera los Named envias por URL
* si es null $key emtraga el array completo de named
*
* #param String $key
*
* #return mixed
*/
protected function getNamed($key=null){
// Is null..?
if(is_string($key)==true){
// get key in array
return Hash::get($this->request->param('named'), $key);
}else{
// all key in array
return $this->request->param('named');
}
}
...
}
I have a similar problem. Not because I have an external system, but because I don't like to put all parameters into the URL-path. In my example, I have some search queries that are assembled and passed to the controller. IMHO, these queries should be GET parameters and not part of the URL-path.
One advantage of using GET parameters is that the order of the given parameters is not important, in contrast to passing params via the URL path.
To solve this problem in a generic way, I'm replacing all method arguments with the value of the GET-param, if one with the same name is given:
class MyController extends AppController
{
function test($var1 = null, $var2 = "content2")
{
foreach (get_defined_vars() as $key => $value) {
if (isset($this->params['url'][$key])) {
$getvalue = $this->params['url'][$key];
$$key = $getvalue;
CakeLog::write("debug", "Setting:$key to $getvalue");
}
}
CakeLog::write("debug", print_r(get_defined_vars(), true));
}
}
Now I can access this controller method and pass parameters via GET like this:
http://myapp/mycontroller/test?var1=foo&var2=bar

Resources