yii2 page caching for single posts - yii2

I have blog via yii2 and using page caching
'class' => 'yii\filters\PageCache',
'only' => ['view','video'],
'duration' => 900,
'dependency' => [
'class' => 'yii\caching\DbDependency',
'sql' => '?',
],
my post table has primary key as id ;
how to I set sql as separate page cache per post id ?
thank you guy .

Just pass the current ID to it and yes, you can do it, use the enabled property and variation like this
[
'enabled' => Yii::$app->request->isGet && Yii::$app->user->isGuest,
'class' => 'yii\filters\PageCache',
'only' => ['index'],
'duration' => 900,
'variations' => [
Yii::$app->request->get('id')
]
]
This ensures that it will cache only get requests for non logged in users per post ID, you don't want to cache other request than get or logged in users if they can do some things like commenting and see per user data (login name etc.)
You can even use a more advanced config if you like eg. dynamic placeholder with page cache to allow caching even for authenticated users, just check the docs.

Related

Yii2 behaviors verbs actions HTTP Methods: post and get

Sometimes, not often, error message appears: "method not allowed yii2 this url can only handle...: POST
Such a code I found in the function behaviors:
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post']
Can it occurs this error message and why this error occurs sometimes(not often)?
ADDitional
Really, I apologize that forget to indicate that all it used by iframe(page open in an iframe window and apply to yii2 through a url and after the delete action was completed - was redirected back), may be a user is logged out, but doest understand it.
And the controller postController receive as post as get method: delete url as GET, _csrf as POST
Only allow delete action via Post. ($_POST). For more security
Example to access via the get and post method: Not recommended for Delete action.
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post','get'],
],
],
Update:
Not always error #405 and may be #403 and ...
Cookies and session expired
When you open several browser tabs(or windows) on your site and your session expires. You login through a window (or with another user). In this case the exception is thrown by clicking on the logut in other open tabs and windows(browser).
This is because CSRF protection works only for unsafe request methods such PUT, POST or DELETE. That's why in order to stay safe your application should never ever use GET requests to change application state.
If a logout by tag <a> or url in nav is set as follows:
'data-method' => 'post'
Modify and try using form and ...
example:
Html::beginForm(['.../logout'], 'post')
. Html::submitButton(
'Logout (' . Yii::$app->user->identity->username . ')',
['class' => 'btn btn-link']
)
. Html::endForm()

Yii2 internationalizating slug and controller

I'm making a yii2 site in 2 languages (for now) using yii's native i18n module, but how can I add multilanguage support for the action URLs?
For instance one of my actions is category/slug and in English, it will show as
http://example.com/category/chair
but in spanish it has to be shown as
http://example.com/categoria/silla
and so on for other languages shown in the future
right now im manually adding my routes like:
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'<alias:\w+>' => 'site/<alias>',
'marca/<slug>' => 'site/brand',
'categoria/<slug>' => 'site/category',
'brand/<slug>' => 'site/brand',
'category/<slug>' => 'site/category',
],
],
Do i need to manually route every action to its correct controller or is it possible to add a more automated form using yii::t() function?
you will need to write your own UrlRule class, implementing yii\web\UrlRuleInterface and configure your UrlManager.
read more here.
basically it is about "translating" a given request like '/categoria/silla' to your internal url ['site/category', 'slug' => $slug, 'lang' => $lang] in your UrlRule's 'parseRequest' method. 'createUrl' is the other way round.

Yii2 -- Pretty Url -- Domain to Controller/Action with parameters

What will be the rules for my pretty url if I have the following scenario:
links like this where parameters may vary.
domain/?bt=<token>&e=<email>
or
domain/?lt=<token>&e=<email>
then should be processed in a controller/action. ie. mycontroller/get
Also, parameters should be accessible by $_GET inside the action.
the simplest way is based on the use of urlHelper
use yii\helpers\Url;
$myUrl = Url::to(['your_controller/your_action', 'bt' => 123, 'e' => 'myemail#gmail.com']);
Using the urlHelper function Url::to .. the url you need is properly formed depending of the urlManager configuration you have set in your config file
and the param a manager as show in the sample like entry in an array.
The post or get method is related to the type of metho you have in your ulr call if not other values are specified the url is formed as a get
and you can obtain the values you need in $_GET['bt'] and $_get['e']
http://www.yiiframework.com/doc-2.0/yii-helpers-url.html
http://www.yiiframework.com/doc-2.0/yii-web-urlmanager.html
http://www.yiiframework.com/doc-2.0/guide-runtime-routing.html
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'<controller:\w+>/<id:\d+>' => '<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
'' => 'call-backs/get',
'unsubscribes' => 'unsubscribes/get',
],
],
#scaisEdge, thank you for answering my question. maybe my question isn't that clear but this is the solution I made for my question after a hard find of clues and tips online.
All I wanted was that when a user clicks on a link, hitting the main page/main domain, it will go to my yii project (intended to be a webservice or an API like one) then will be handled by a precise controller and action.
'' => 'call-backs/get'
the code above answers the question. Cheers.

Differentiate between Frontend and Backend Logs in DBTarget Yii2

I am logging into Db using existing Yii logging API.
But I want to differentiate between Frontend logs and Backend logs inside DB.
Everything that appears is common for both, I face difficulty tracing frontend logs.
Below is the image of DB Logs where GREEN marked are for backend logs, RED marked are for Frontend Logs.
You can use prefix property for this. This is callable that returns a string to be prefixed to every exported message with signature function ($message).
As default getMessagePrefix() is used there which prefixes the message with user IP, user ID and session ID.
You can use it to add there frontend and backend.
Thanks to #Bizley!
Inside both backend/config/main and frontend/config/main, I configured below; This is how my entire log configuration for Frontend looks like(Similarly you can do it for Backend);
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\DbTarget',
'levels' => ['error'],
'prefix' => function ($message) {
return "[Frontend]";
},
],
[
'class' => 'yii\log\FileTarget',
'levels' => ['error','info'],
],
],
],
Below is the view on UI for logs. With the Help of Prefix I can now easily differentiate between channels.

Join Table with the id of another join table

i'm currently trying to build a backend for a project. In this project you will be able to create "ContentElements" that can be used to display content in a page (in my case Sites). Every ContentElement can have multiple options. When a user creates a new Site with an ContentElement (e.g. header) he would enter all options of the element. For example:
"src": "/img/bg.jpg",
"text": "Lorem ipsum..."
In order to save the option's value per page it is used in, i store these values in a separate table (content_elements_sites_values).
My scheme currently looks like this: data scheme
So what i'm currently trying to do is when i get all data associated with the Site i also want to get the data from 'content_elements_sites_values'
$site = $this->Sites->get($id, [
'contain' => ['Templates', 'Colors', 'SiteTypes', 'ContentElements' => [
'ContentElementOptions' => [
'ContentElementsSitesValues'
]
]
],
'conditions' => [
// Just to explain my problem.
'ContentElementsSites.id' => 'ContentElementsSitesValues.content_elements_sites_id'
]
]);
I really don't know if this is even possible or even if my "design" is a total bull***t. But i cannot think of another way to store the filled in data. I'm very open to suggestions of a better way to store this data. Please ask if you need further information in order to help me.
Thank you in advance!
EDIT
I try to explain better what i want to achieve.
Every site can have multiple content_elements of the same type (association is stored in content_elements_sites junction table).
Every content_element can have multiple content_element_options
All content_element_options and content_elements are defined by an Admin.
Another user can create a site and populate it with content_elements and enter content_elements_sites_value for all content_element_options. And as the same content_element (e.g. a paragraph or a list) can have multiple occurrences in the same site, i'll need to store every content_elements_sites_value the user entered.
Thats why i created the link between content_elements_sites and content_element_options.
Currently i'm using this query to get everything expect the value:
$site = $this->Sites->find('all', [
'conditions' => [
'Sites.id' => $id
],
'contain' => ['ContentElements' => [
'sort' => [
'ContentElementsSites.order' => 'ASC'
],
'ContentElementOptions' => [
'ContentElementsSitesValues' => [
'conditions' => [
'ContentElementsSitesValues.content_elements_sites_id' => 'ContentElementsSites.id',
]
]
]
]
]
]);
This results in empty content_elements_sites_values
(int) 1 => object(App\Model\Entity\ContentElementOption) {
'id' => (int) 7,
'content_element_id' => (int) 1,
'name' => 'Test',
'json_name' => 'test',
'option_type_id' => (int) 1,
'content_elements_sites_value' => null,
}
My scheme currently looks like this: data scheme
I'm wondering if this query is even possible. Or if the whole thing is just too flexible.
The way you have defined the relationships signifies that you wish to have a very modular approach so that a content element can be used with multiple sites and a content element option can be used with multiple content elements.
If that is the case, schema direction looks okay with few changes :
1) content_elements_sites_values table can have site_id column directly instead of content_elements_sites_id column as site will be always unique for an entry in that table so the connection id of content_elements_sites isn't required.
2) content_elements_sites_values table can be renamed to content_element_options_values.
3) You can remove id column from content_elements_sites and content_elements_sites_values junction tables.
maybe this is what you are looking for :
$site = $this->Sites->get($id, [
'contain' => ['Templates', 'Colors', 'SiteTypes', 'ContentElements', 'ContentElements.ContentElementOptions','ContentElements.ContentElementOptions.ContentElementsSitesValues'],
....]);
dont forget to define association relationship in model table.