How can i fetch dynamic data from database based on selected language.? - database

Hi i am working on a project in laravel 7.0, in back-end i have a table called Posts which contains 2 text language input one in french and the other is arabic added by the back-end application.
what i am trying to do is when the user uses the French Language i want the title_fr to be displayed on the view and same thing in Arabic language the title should be title_ar.
P.S data are stored in French and Arabic
I have tried the similar solution given in an other similar question but none of it worked in my case!
Any idea how i might get this to work ?
Thanks in advance.

You can do something similar to below. We have a model Post, this model has an attribute title. I also assume that you have an attribute that will return user's language from the User model.
class Post extends Model
{
public function getTitleAttribute(): string
{
return Auth::user()->language === 'fr' ? $this->title_fr : $this->title_ar;
}
}
FYI above is just a demo on what can be done. For a full blow solution I would recommend decorator pattern.
Also it might be worth considering using morph for things like that. You can have a service provider that will initiate the morph map for you post model relevant to the language that user has, I.e.
Class ModelProvider {
Protected $models = [
‘fr’ => [
‘post’ => App/Models/Fr/Post::class,
],
‘ar’ => [
‘post’ => App/Models/Ar/Post::class,
]
];
Public function boot() {
$language = Auth::user()->Settings->language;
Relation::morphMap($This->models[$language]);
}
}
Afterwards you just need to call to Relation::getMorphModel(‘post’) to grab Post class that will return correct language.
I.e. App/Models/Fr/Post can have a an attribute title:
Public function getTitleAttribute(): string {
Return $this->title_fr;
}
For example above you would also want to utilise interfaces to make sure that all models follow the same contract, something below would do the trick:
Interface I18nPostInterface {
Public function getTitleAttribute(): string
}
Also, depending on the database you use, to store titles (and other language data) in a JSON format in the database. MySQL 8 has an improve support for JSON data, but there are limitations with that.

So I was Able to fetch data from my database based on the Language selected by the user.
Like i said before I have a table called Posts and has columns id,title_fr and title_ar. I am using laravel Localization.
Inside my PostController in the index function i added this code:
public function index()
{
//
$post = Post::all();
$Frtitle = post::get()->pluck('title_fr');
$Artitle = post::get()->pluck('title_ar');
return view('post.index',compact('post','Frtitle','Artitle'));
}
if anyone has a better way then mine please let me know, i am sure
there is a better way.

Related

CakePHP How to create pagination from API JSON data source

I have an API like example
I have used cakephp HTTP client to get data, below my attempted code
public index()
{
$http = new Client();
$response = $http->get('https://restcountries.eu/rest/v2/all');
// $json = $response->getJson(); //also tried usgin json
$countries = $this->paginate($response);
$this->set(compact('countries '));
}
I am trying to apply pagination with this country data then fetch it in view with pagination.
After tried above code , I have gotten below error
Argument 1 passed to Cake\Datasource\Paginator::extractData() must be an instance of Cake\Datasource\RepositoryInterface, instance of Cake\Http\Client\Response given, called in \myapp\vendor\cakephp\cakephp\src\Datasource\Paginator.php on line 176
How can I get my desire result ?
You have probably need to implement a class who extend RepositoryInterface.
class JsonSource implements Cake\Datasource\RepositoryInterface
{ ... }
public index() {
$http = new Client();
$response = $http->get('https://restcountries.eu/rest/v2/all');
$src = new JsonSource();
$src->fromResponse($response);
$countries = $this->paginate($src);
$this->set(compact('countries ')); }
Is a bit tedious, because you need to define Json like a datasource.
The default pagination only supports querying tables (repositories), or operating on pre-built query instances.
To extend on #Zeppi's answer. You basically have three somewhat straightforward options here:
Create custom query/repository implementations as hinted by #Zeppi.
This can indeed be quite a lot of work though, so you might want to look into alternatively implementing it with the help of plugins, for example muffin/webservice, which does most of the hard work of implementing the required interfaces.
Or create a custom paginator that actually accepts and works on array data.
Or use what is widely know as a "datatable", that is a JavaScript based table in the frontend that paginates the data, for example jQuery DataTables.

Yii2 + Redis as Database

I want to use Yii2 and redis as database.
So far, I got Redis ActiveRecord Class for Yii2 from Here.
link1
link2
but, I got a problem. WHY THIS CLASS ADDS ANYTHING AS HASH IN REDIS????
Above that I cant Find in which pattern it Insert data. I add one user and it will add a user under user:xxx namespace and another record under s:user:xxx and so on but none of theme has any fields that i defined in attributes!! only contain IDs.
I know that a Key-value type database and RDBMS are different and also know how can implement relation like records in Redis, but I don't know why it will only save IDs.
I could not find any example of using redis ActiveRecords so far.
There is one in here and its not good enough.
So here is my main wuestion: how can add data to redis Using activeRecords and different data types In YII2?
And if its impossible with ActiveRecords what is the best solution? in this case
ANOTHER QUESTION: is it possible to use a Model instead and write my own model::save() method? and what is the best data validation solution at this rate?
Actually I want to make a telegram bot, so i should get messages and send them in RabitMQ and get data in a worker, do the process and save results to Redis, and finally send response to user through the RabitMQ.
So I need to do a lot of validations AND OF COURSE AUTHENTICATIONS and save and select and range and save to sets an lists and this and that ....
I want a good way to make Model or active record or the proper solution to validation, save and retrieve data to Redis and Yii2.
Redis DB can be declared as a cache component or as a database connection or both.
When it is declared as a cache component (using the yii/redis/cache) it is accessible within that component to store key/value pairs as shown here.
$cache = Yii::$app->cache;
// try retrieving $data from cache
$data = $cache->get($key);
// store $data in cache so that it can be retrieved next time
$cache->set($key, $data);
// one more example:
$access_token = Yii::$app->security->generateRandomString();
$cache->add(
// key
$access_token,
// data (can also be an array)
[
'id' => Yii::$app->user->identity->id
'name' => Yii::$app->user->identity->name
],
// expires
60*60*3
);
Also other components may start using it for caching proposes like session if configured to do so or like the yii\web\UrlManager which by default will try to cache the generated URL rules in whatever valid caching mechanism defined under the config file's cache component as explained here. So it is normal to find some stored data other than yours in that case.
When Redis is declared as a DB connection like in the links you provided which means using the yii\redis\Connection class you can make your model extending its \yii\redis\ActiveRecord class as any other ActiveRecord model in Yii. The only difference I know so far is that you need to define your attributes manually as there is no DB schema to parse for NoSQL databases. Then just define your rules, scenarios, relations, events, ... as any other ActiveRecord model:
class Customer extends \yii\redis\ActiveRecord
{
public function attributes()
{
return ['id', 'name', 'address', 'registration_date'];
}
public function rules()
{
return [
['name', 'required'],
['name', 'string', 'min' => 3, 'max' => 12, 'on' => 'register'],
...
];
}
public function attributeLabels() {...}
...
}
All available methods including save(), validate(), getErrors(), ... could be found here and should be used like any other ActiveRecord class as shown in the official guide.

CakePHP: Scaffolding after having written edit/view/add

I have an application in which we give a very friendly interface for managing data. This is done through many controllers' add/edit/view functions. But now the requirement has come that we should have "super admins" able to edit anything, and scaffolding will give them a quick and dirty manner of changing data. Since scaffolding uses add/edit/view by default, I've unintentionally overwritten the ability to scaffold.
I can't just go and change all my calls to edit/add for our "user friendly" data managing. So I want to essentially ignore the add/edit/view when, for example, a user has a flag of "yes, please let me scaffold". I imagined it would be something like:
public function edit($id) {
if (admin_user) {
$scaffold;
} else {
[user-friendly version code]
}
}
But no dice. How can I achieve what I want?
suppose you already have admin users and you want to scaffold only super-user:
Also suppose you store the information about beeing a super-user or not in a column named super in the users table
in your core.php
Configure::write('Routing.prefixes', array('admin', 'super));
in your appController
public $scaffold = 'super';
beforFilter() {
if($this->Auth->user('super') && !isset($this->params['super'])
$this->redirect(array('super' => true));
}
Now I can't try this code but the idea should work.
edit: we need to check if we are already in a super_action to avoid infinite redirect

How to set up CakePHP 2.x to behave like a RESTful webservices (for using it together with JavascriptMVC)

I am trying to set up cakephp to work with the very nice javascriptMVC (http://forum.javascriptmvc.com). JavaScriptMVC requires the JSON-Output in the following format:
[{
'id': 1,
'name' : 'Justin Meyer',
'birthday': '1982-10-20'
},
{
'id': 2,
'name' : 'Brian Moschel',
'birthday': '1983-11-10'
}]
Cake would generate a deeper nested array with a prepended Class Name. I found attempts to solve the problem but theyre not for cakephp 2.x. I know that I can simply generate a new array and json_encode() it via php, but it would be nicer to include a function like this https://gist.github.com/1874366 and another one to deflatten it.
Where would be the best place to put such functions? The AppController doesnt seem to work. Should i put it in beforeRender () or beforeFilter() of the controller? Or does someone maybe even know of an existing solution/plugin for this? This would be the best for me in my current Situation, as Im pretty much pressed for time.
Ok, I'm not 100% sure I understand what you are trying to do so here's a word to the wise just in case: Cake and JMVC are both comprehensive MVC frameworks. if you are attempting to combine them as a single cohesive platform to build your application, I strongly suggest you review your approach / platform / etc.
Also -- I'm not an expert by any means in jmvc, so I'm just going to pretend that processing the response from Cake in jmvc is completely out of the question, for some odd reason. For the record, think of Cake's responses like this:
{ "Model" :
[{
'id': 1,
'name' : 'Justin Meyer',
'birthday': '1982-10-20'
},
{
'id': 2,
'name' : 'Brian Moschel',
'birthday': '1983-11-10'
}]
}
Cake has had comprehensive REST service support, since at least Cake 1.2. The lib you are interested in is HttpSocket. As for json encoding and serving response, Request Handling covers, among other things, responding to all manners of requests, content types, decoding and encoding json, etc. Finally, the built-in Set utility will almost certainly cover whatever array manipulation you need in a line or two.
The functionality you are interested in is pretty basic and hasn't changed too much. I'd bet a lot of the (reasonably simple) solutions you have already found would probably still work, maybe with a little bit of tweaking.
For pretty much any basic service endpoint, you would probably create a controller (not AppController - that is application-wide, hence you can't invoke it directly) method, considering Cake routes the controller/action into your url:
Cake consuming services from a different app would look like this:
http://cakeproject/collect/getInfo
class CollectController extends AppController {
public function getInfo($array = null) {
App::uses('HttpSocket', 'Network/Http');
$http = new HttpSocket();
$http->get('http://jmvcproject/controller/action', $array);
// ...etc.
}
Cake providing services from the same controller / action to a different app would simply be:
public function getInfo($array = null) {
$results = $this->Collect->find('all', $array);
// ...fetch the results
}
Or you could just loop over that array with foreach($this->data as $data) { ... to drop the class name. But if your data will include associated models, etc, Set is probably the most versatile and resilient solution.
Anyway, HTH

Computing table name from model name

In my CakePHP application, I have a model like this:
class Duck extends AppModel {
var $name = 'Duck';
function get_table_name() {
$tbl_name = //compute default table name for this model
}
}
I would like to write the function get_table_name() that outputs the default table name for the model. For the example above, it should output ducks.
EDIT:
Several people have pointed out the use of $this->table.
I did small testing and found out the following:
In the question as I have put above, $this->table indeed contains the table name.
However, actually, my code looked more like this:
class Duck extends Bird {
var $name = 'Duck';
function get_table_name(){
$tbl_name = //comput default table name for this model
}
}
class Bird extends AppModel {
}
In this case $this->table is empty string.
I went with this approach because I wanted to share some code between two of my models. Looks like this is not a good way to share code between models which need some common functionality.
You're looking for the Inflector class.
Inflector::tableize($this->name)
(tableize calls two Inflector methods to generate the table name: underscore() and pluralize())
Edit:
According to the source code, $this->table should contain the name of the table that CakePHP will use for the model, but in my experience this isn't always set. I'm not sure why.
To get the name of the table that the model is currently using, you can use: $this->table. If you don't manually change the model's table conventions, this may be the most useful in the case of CakePHP ever changing its conventions to use table names using something other than Inflector.
CakePHP's Inflector
function get_table_name() {
$tbl_name = Inflector::pluralize($this->name);
}
OR the tableize method
function get_table_name() {
$tbl_name = Inflector::tableize($this->name);
}
Edit
This also addresses the apparent "ghost" issue with $this->table in the Model.
Digging around in the __construct for Model I discovered two things:
Cake uses Inflector::tableize() to get the table name. This alone is enough to warrant using tableize over pluralize. You'll get consistent results.
$this->table is not set by the Model::__construct() unless $this->useTable === false AND $this->table === false.
It appears that if you know you haven't set $this->useTable to false you should be able to use this over $this->table. Admittedly though I only briefly scanned the source and I haven't really dug deep enough to say why $this->table isn't working sometimes.
To get the full table name for a model you have to take the table prefix into account.
$table = empty($this->table) ? Inflector::tableize($this->name) : $this->table;
$fullTableName = $this->tablePrefix . $table;
I used to use inflector to get the table name from model's name
$tableName = Inflector::pluralize(Inflector::underscore($model));
but this is not really universal, using useTable looks better, by default it will contain table's name by convention, and if you have a table that does not match the conventions, then you should manually specify it by useTable. So, in both cases the result will be correct
$this->User->useTable

Resources