Live News for Yii Framework News, fresh extensions and wiki articles about Yii framework. Tue, 25 Sep 2018 00:59:35 +0000 Zend_Feed_Writer 2 (http://framework.zend.com) https://www.yiiframework.com/ [extension] abushamleh/yii2-sprout-video Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/extension/abushamleh/yii2-sprout-video https://www.yiiframework.com/extension/abushamleh/yii2-sprout-video Abdelhadi92 Abdelhadi92

yii2-sproutVideo

  1. Installation
  2. list_videos
  3. get_video
  4. create_video
  5. update_video
  6. replace_video
  7. Tags
  8. Upload poster frame
  9. delete_video
  10. Signed Embed Codes
  11. create_upload_token
  12. list_tags
  13. create_tag
  14. update_tag
  15. delete_tag
  16. list_playlists
  17. create_playlist
  18. update_playlist
  19. d elete_playlist
  20. list
  21. create_login
  22. get_login
  23. update_login
  24. delete_login
  25. list_access_grants
  26. create_access_grant
  27. get_access_grant
  28. update_access_grant
  29. delete_access_grant
  30. get_account
  31. update_account

Yii2 client for SproutVideo (http://sproutvideo.com)

Installation

  1. Run the Composer command to install the latest version:

    `bash composer require abushamleh/yii2-sprout-video "dev-master" `

  2. Add the component to config/main.php

    `php 'components' => [

     // ...
     'sproutVideo' => [
         'class'   => 'abushamleh\sproutVideo\Client',
         'api_key' => 'your api key',
     ],
     // ...
    

    ], `

Videos

  1. Installation
  2. list_videos
  3. get_video
  4. create_video
  5. update_video
  6. replace_video
  7. Tags
  8. Upload poster frame
  9. delete_video
  10. Signed Embed Codes
  11. create_upload_token
  12. list_tags
  13. create_tag
  14. update_tag
  15. delete_tag
  16. list_playlists
  17. create_playlist
  18. update_playlist
  19. d elete_playlist
  20. list
  21. create_login
  22. get_login
  23. update_login
  24. delete_login
  25. list_access_grants
  26. create_access_grant
  27. get_access_grant
  28. update_access_grant
  29. delete_access_grant
  30. get_account
  31. update_account

The following methods are available: list_videos, get_video, create_video, update_video, replace_video, delete_video.

list_videos

By default the videos listing is paginated with 25 videos per page and sorted by upload date in ascending order. You can pass two parameters to control the paging: page and per_page. You can also pass in the id of a tag to just return the videos tagged with that tag.

<?php
Yii::$app->sproutVideo->video::list_videos();
Yii::$app->sproutVideo->video::list_videos(array('per_page' => 10));
Yii::$app->sproutVideo->video::list_videos(array('per_page' => 10, 'page' => 2));
Yii::$app->sproutVideo->video::list_videos(array('tag_id' => 'abc')));
?>

get_video

The string passed to get_video is the ID of a SproutVideo video.

<?php
Yii::$app->sproutVideo->video::get_video('abc123');
?>

create_video

The most basic upload you can perform is to just pass the path to the video file to the method. The title of the video will default to the name of the file.

<?php
Yii::$app->sproutVideo->video::create_video('/path/to/video.mp4');
?>

You can set the title as well as many other parameters by passing them as a array

`php <?php Yii::$app->sproutVideo->video::create_video('/path/to/video.mp4', array('title' => 'My Awesome Video', 'description' => 'This video is great', 'privacy' => 2)); ?> `

You can also apply any number of tags to the new upload by passing their ids along:

<?php
Yii::$app->sproutVideo->video::create_video('/path/to/video.mp4', array('tags' => array('ec61', 'abc123'));
?>

You can also create and apply tags on the fly when uploading by passing along tag names:

<?php
Yii::$app->sproutVideo->video::create_video('/path/to/video.mp4', array('tag_names' => array('Tag One', 'Tag Two'));
?>

You can also specify a webhook url. We'll send an HTTP POST with the video json when the video has finished processing or if there was an error during processing:

<?php
Yii::$app->sproutVideo->video::create_video('/path/to/video.mp4', array('notification_url' => 'http://example.com/webhook_url'));
?>

update_video

The first parameter is the id of the video you wish to edit. The second parameter is a array of attributes to update on the video.

<?php
Yii::$app->sproutVideo->video::update_video('abc123', array('title' => 'Updated Title'));
?>

replace_video

The first parameter is the id of the video you wish to replace. The second parameter is the local path to the video file.

<?php
Yii::$app->sproutVideo->video::replace_video('abc123', '/path/to/video.mp4');
?>

Tags

To add a tag to a video, make sure to include all of the tags currently associated with the video. For instance, if the video already has tags with the ids "abc" and "123", and you want to add a tag with the id "def", pass "abc", "123" and "def" to the update method.

<?php
Yii::$app->sproutVideo->video::update_video('abc123', 'tags' => array("abc", "123", "def"));
?>

If you want to remove a tag from a video, remove the tag from the list of tags on the video but make sure to include all of the tags you wish to keep. For instance, if you now want to remove the tag with id "123" from the example above, pass in "abc" and "def"

<?php
Yii::$app->sproutVideo->video::update_video("abc123", array('tags' => array("abc","def"));
?>

You can remove all of the tags from a video by just passing an empty array as the tags parameter.

<?php
Yii::$app->sproutVideo->video::update_video('abc123', array('tags' => array()));
?>

Upload poster frame

You can upload a custom poster frame for a video by calling the upload_poster_frame method. The first parameter is the id of the video for wish you'd like the poster frame to be associated and the second parameter is the path to the image file. `php <?php Yii::$app->sproutVideo->video::upload_poster_frame('abc123','/path/to/video.mp4'); ?> `

delete_video

Pass in the id of the video you wish to delete.

<?php
Yii::$app->sproutVideo->video::delete_video('abc123');
?>

Signed Embed Codes

You can use this convenience method to sign an embed code. It will return the embed code URL which can be used to build an iframe embed code.

<?php
Yii::$app->sproutVideo->video::signed_embed_code($video_id, $security_token, $query_parameters, $expiration_time, $protocol);
?>
Parameters

video_id - String ( Required ) : The id of the video for which you're generating the signed embed code

security_token - String ( Required ) : The security token of the video for which you're generatingn the signed embed code

query_parameteres - Array ( Optional ) : A array of query parameters to be passed to the embed code. Example: array('type' => 'hd', 'autoplay' => 'true')

expiration_time - Integer ( Optional ) : The number of seconds from the Epoc that this signed embed code should expire. This defaults to 5 minutes from the time the signed embed code was generated.

protocol - String ( Optional ) : http or https. Defaults to http

Examples
<?php
Yii::$app->sproutVideo->video::signed_embed_code('abc123','def456'); #sign a base embed code with no other options
Yii::$app->sproutVideo->video::signed_embed_code('abc123','def456', array('type' => 'hd')); #set parameters for the embed code such as changing the default video type to HD
Yii::$app->sproutVideo->video::signed_embed_code('abc123','def456', array(), 1368127991); #set a specific expiration time for the signed embed code. (By default the expiration time is set to 5 minutes from the time the signed embed code was generated).
Yii::$app->sproutVideo->video::signed_embed_code('abc123','def456', array(), null, 'https'); #Use https instead of http
?>

Upload Tokens

  1. Installation
  2. list_videos
  3. get_video
  4. create_video
  5. update_video
  6. replace_video
  7. Tags
  8. Upload poster frame
  9. delete_video
  10. Signed Embed Codes
  11. create_upload_token
  12. list_tags
  13. create_tag
  14. update_tag
  15. delete_tag
  16. list_playlists
  17. create_playlist
  18. update_playlist
  19. d elete_playlist
  20. list
  21. create_login
  22. get_login
  23. update_login
  24. delete_login
  25. list_access_grants
  26. create_access_grant
  27. get_access_grant
  28. update_access_grant
  29. delete_access_grant
  30. get_account
  31. update_account

The following methods are available: create_upload_token

create_upload_token

<?php
Yii::$app->sproutVideo->uploadToken::create_upload_token();
Yii::$app->sproutVideo->uploadToken::create_upload_token(array('return_url' => 'http://example.com'));
Yii::$app->sproutVideo->uploadToken::create_upload_token(array('return_url' => 'http://example.com', 'seconds_valid' => 3600));
?>

Tags

  1. Installation
  2. list_videos
  3. get_video
  4. create_video
  5. update_video
  6. replace_video
  7. Tags
  8. Upload poster frame
  9. delete_video
  10. Signed Embed Codes
  11. create_upload_token
  12. list_tags
  13. create_tag
  14. update_tag
  15. delete_tag
  16. list_playlists
  17. create_playlist
  18. update_playlist
  19. d elete_playlist
  20. list
  21. create_login
  22. get_login
  23. update_login
  24. delete_login
  25. list_access_grants
  26. create_access_grant
  27. get_access_grant
  28. update_access_grant
  29. delete_access_grant
  30. get_account
  31. update_account

The following methods are available: list_tags, create_tag, get_tag, update_tag, delete_tag.

list_tags

By default the tag listing is paginated with 25 tags per page and sorted by created at date in ascending order. You can pass two parameters to control the paging: page and per_page.

<?php
Yii::$app->sproutVideo->tag::list_tags();
Yii::$app->sproutVideo->tag::list_tags('per_page' => 10);
Yii::$app->sproutVideo->tag::list_tags('per_page' => 10, 'page' => 2);
?>

create_tag

<?php
Yii::$app->sproutVideo->tag::create_tag(array('name' => 'new tag'));
?>

update_tag

<?php
Yii::$app->sproutVideo->tag::update_tag('abc123', array('name' => 'updated tag name'));
?>

delete_tag

Pass in the id of the tag you wish to delete.

<?php
Yii::$app->sproutVideo->tag::delete_tag('abc123');
?>

Playlists

  1. Installation
  2. list_videos
  3. get_video
  4. create_video
  5. update_video
  6. replace_video
  7. Tags
  8. Upload poster frame
  9. delete_video
  10. Signed Embed Codes
  11. create_upload_token
  12. list_tags
  13. create_tag
  14. update_tag
  15. delete_tag
  16. list_playlists
  17. create_playlist
  18. update_playlist
  19. d elete_playlist
  20. list
  21. create_login
  22. get_login
  23. update_login
  24. delete_login
  25. list_access_grants
  26. create_access_grant
  27. get_access_grant
  28. update_access_grant
  29. delete_access_grant
  30. get_account
  31. update_account

The following methods are available: list_playlists, create_playlist, get_playlsit, update_playlist, delete_playlsit.

list_playlists

By default the playlist listing is paginated with 25 playlists per page and sorted by created at date in ascending order. You can pass two parameters to control the paging: page and per_page.

<?php
Yii::$app->sproutVideo->playlist::list_playlists();
Yii::$app->sproutVideo->playlist::list_playlists(array('per_page' => 10));
Yii::$app->sproutVideo->playlist::list_playlists(array('per_page' => 10, 'page' => 2));
?>

create_playlist

You can add videos to a playlist when creating it by passing in the videos you'd like to add in the videos parameter in the order you'd like them to appear.

<?php
Yii::$app->sproutVideo->playlist::create_playlist(array(
  'title' => 'New Playlist',
  'privacy' => 2,
  'videos' => array('abc123','def456','ghi789'));
?>

update_playlist

<?php
Yii::$app->sproutVideo->playlist::update_playlist('abc123', array('title' => 'Update Playlist Title'));
?>
videos

To add a video to a playlist, make sure to include all of the videos currently associated with that playlist. For instance if the playlist already has videos with the ids "abc" and "123" and you want to add a video with the id "def" do pass "abc", "123" and "def" to the update method.

<?php
Yii::$app->sproutVideo->playlist::update_playlist('abc123', array('videos' => array("abc", "123", "def")));
?>

If you want to remove a video from a playlist, remove the video from the list of videos in the playlist but make sure to include all of the videos you wish to keep. For instance, if you now want to remove the video with id "123" from the example above, pass in "abc" and "def"

<?php
Yii::$app->sproutVideo->playlist::update_playlist("abc123", array('videos' => array("abc","def")));
?>

You can remove all of the videos from a playlist by just passing an empty array as the videos parameter.

<?php
Yii::$app->sproutVideo->playlist::update_playlist('abc123', array('videos' => array()));
?>

d elete_playlist

Pass in the id of the playlist you wish to delete.

<?php
Yii::$app->sproutVideo->playlist::delete_playlist('abc123');
?>

Logins

  1. Installation
  2. list_videos
  3. get_video
  4. create_video
  5. update_video
  6. replace_video
  7. Tags
  8. Upload poster frame
  9. delete_video
  10. Signed Embed Codes
  11. create_upload_token
  12. list_tags
  13. create_tag
  14. update_tag
  15. delete_tag
  16. list_playlists
  17. create_playlist
  18. update_playlist
  19. d elete_playlist
  20. list
  21. create_login
  22. get_login
  23. update_login
  24. delete_login
  25. list_access_grants
  26. create_access_grant
  27. get_access_grant
  28. update_access_grant
  29. delete_access_grant
  30. get_account
  31. update_account

The following methods are available: list_logins, create_login, get_login, update_login, delete_login

list

By default the login listing is paginated with 25 tags per page and sorted by created at date in ascending order. You can pass two parameters to control the paging: page and per_page.

<?php
Yii::$app->sproutVideo->login::list_logins();
Yii::$app->sproutVideo->login::list_logins(array('per_page' => 10));
Yii::$app->sproutVideo->login::list_logins(array('per_page' => 10, 'page' => 2));
?>

create_login

create_login takes two required parameters, email and password, which will be used to allow a viewer to login to watch a video if the login has an associated access_grant for that video.

<?php
Yii::$app->sproutVideo->login::create_login(array(
  'email' => 'test@example.com',
  'password' => 'thisisthepassword'));
?>

get_login

The string passed to get_login is the ID of a SproutVideo login.

<?php
Yii::$app->sproutVideo->login::get_login('abc123');
?>

update_login

You can change the password for a login.

<?php
Yii::$app->sproutVideo->login::update_login('abc123',array(
  'password' => 'newpassword'));
?>

delete_login

Pass in the id of the login you wish to delete.

<?php
Yii::$app->sproutVideo->login::delete_login('asdf1234');
?>

Access Grants

  1. Installation
  2. list_videos
  3. get_video
  4. create_video
  5. update_video
  6. replace_video
  7. Tags
  8. Upload poster frame
  9. delete_video
  10. Signed Embed Codes
  11. create_upload_token
  12. list_tags
  13. create_tag
  14. update_tag
  15. delete_tag
  16. list_playlists
  17. create_playlist
  18. update_playlist
  19. d elete_playlist
  20. list
  21. create_login
  22. get_login
  23. update_login
  24. delete_login
  25. list_access_grants
  26. create_access_grant
  27. get_access_grant
  28. update_access_grant
  29. delete_access_grant
  30. get_account
  31. update_account

The following methods are available: list_access_grants, create_access_grant, get_access_grant, update_acces_grant, delete_access_grant

list_access_grants

By default the access grant listing is paginated with 25 tags per page and sorted by created at date in ascending order. You can pass two parameters to control the paging: page and per_page.

<?
Yii::$app->sproutVideo->accessGrant::list_access_grants();
Yii::$app->sproutVideo->accessGrant::list(array('per_page' => 10));
Yii::$app->sproutVideo->accessGrant::list(array('per_page' => 10, 'page' => 2));
?>

create_access_grant

create_access_grant takes two required parameters, video_id and login_id, which will be used to allow a viewer to login to watch a video based on the other optional parameters.

<?php
Yii::$app->sproutVideo->accessGrant::create_access_grant(array(
  'video_id' => 'abc123',
  'login_id' => 'abc123'));
?>

get_access_grant

The string passed to get_access_grant is the ID of a SproutVideo login.

<?php
Yii::$app->sproutVideo->accessGrant::get_access_grant('abc123');
?>

update_access_grant

You can change the optional parameters for an access grant.

<?php
Yii::$app->sproutVideo->accessGrant.update_access_grant('abc123', array(
  'allowed_plays' => 20,
  'access_ends_at' => '2015-04-15T00:00:00+00:00'));
?>

delete_access_grant

Pass in the id of the access grant you wish to delete.

<?php
Yii::$app->sproutVideo->accessGrant::delete_access_grant('asdf1234')
?>

Analytics

  1. Installation
  2. list_videos
  3. get_video
  4. create_video
  5. update_video
  6. replace_video
  7. Tags
  8. Upload poster frame
  9. delete_video
  10. Signed Embed Codes
  11. create_upload_token
  12. list_tags
  13. create_tag
  14. update_tag
  15. delete_tag
  16. list_playlists
  17. create_playlist
  18. update_playlist
  19. d elete_playlist
  20. list
  21. create_login
  22. get_login
  23. update_login
  24. delete_login
  25. list_access_grants
  26. create_access_grant
  27. get_access_grant
  28. update_access_grant
  29. delete_access_grant
  30. get_account
  31. update_account

The following methods are available through the API client for analytics:

  • play_counts
  • domains
  • geo
  • video_types
  • playback types
  • device_types

Check the API documentation for more information about the data returned by these calls.

Each method can be called on it's own for overall account data for all time like this: `php <?php Yii::$app->sproutVideo->analytics::play_counts(); Yii::$app->sproutVideo->analytics::domains(); Yii::$app->sproutVideo->analytics::geo(); Yii::$app->sproutVideo->analytics::video_types(); Yii::$app->sproutVideo->analytics::playback_types(); Yii::$app->sproutVideo->analytics::device_types(); ?> Each method can also take an options array containing a :video_id for retrieving overall data for a specific video:php <?php Yii::$app->sproutVideo->analytics::play_counts(array('video_id' => 'abc123')); Yii::$app->sproutVideo->analytics::domains(array('video_id' => 'abc123')); Yii::$app->sproutVideo->analytics::geo(array('video_id' => 'abc123')); Yii::$app->sproutVideo->analytics::video_types(array('video_id' => 'abc123')); Yii::$app->sproutVideo->analytics::playback_types(array('video_id' => 'abc123')); Yii::$app->sproutVideo->analytics::device_types(array('video_id' => 'abc123')); ?> Each method can also take an optional :start_date and :end_date to specify a date range for the returned data:php <?php Yii::$app->sproutVideo->analytics::play_counts(array('start_date' => '2013-01-01')); Yii::$app->sproutVideo->analytics::device_types(array('video_id' => 'abc123', 'end_date' => '2012-12-31')); ?> `

Lastly, the geo method can take an optional :country to retrieve playback data by city within that country `php <?php Yii::$app->sproutVideo->analytics::geo(array('video_id' => 'abc123', 'country' => 'US')); ?> `

Engagement

  1. Installation
  2. list_videos
  3. get_video
  4. create_video
  5. update_video
  6. replace_video
  7. Tags
  8. Upload poster frame
  9. delete_video
  10. Signed Embed Codes
  11. create_upload_token
  12. list_tags
  13. create_tag
  14. update_tag
  15. delete_tag
  16. list_playlists
  17. create_playlist
  18. update_playlist
  19. d elete_playlist
  20. list
  21. create_login
  22. get_login
  23. update_login
  24. delete_login
  25. list_access_grants
  26. create_access_grant
  27. get_access_grant
  28. update_access_grant
  29. delete_access_grant
  30. get_account
  31. update_account

You can grab the total number of seconds of your videos that have been watched like this: `php <?php Yii::$app->sproutVideo->analytics::engagement(); ?> `

You can grab engagement for a specific video like so: `php <?php Yii::$app->sproutVideo->analytics::engagement(array('video_id' => 'abc123')); ?> `

Lastly, you can grab every single playback session for a video like this: `php <?php Yii::$app->sproutVideo->analytics::engagement_sessions('abc123') Yii::$app->sproutVideo->analytics::engagement_sessions('abc123', array('page' => 3)); Yii::$app->sproutVideo->analytics::engagement_sessions('abc123', array('page' => 3, 'per_page' => 40)); ?> `

You can also grab engagement sessions for a video for a specific email address like so: `php <?php Yii::$app->sproutVideo->analytics::engagement_sessions('abc123', array('vemail' => 'test@example.com')); ?> `

Account

  1. Installation
  2. list_videos
  3. get_video
  4. create_video
  5. update_video
  6. replace_video
  7. Tags
  8. Upload poster frame
  9. delete_video
  10. Signed Embed Codes
  11. create_upload_token
  12. list_tags
  13. create_tag
  14. update_tag
  15. delete_tag
  16. list_playlists
  17. create_playlist
  18. update_playlist
  19. d elete_playlist
  20. list
  21. create_login
  22. get_login
  23. update_login
  24. delete_login
  25. list_access_grants
  26. create_access_grant
  27. get_access_grant
  28. update_access_grant
  29. delete_access_grant
  30. get_account
  31. update_account

The following methods are available: get_account, update_account.

get_account

<?php
Yii::$app->sproutVideo->account::get_account();
?>

update_account

<?php
Yii::$app->sproutVideo->account::update_account(array('download_hd' => true));
?>
]]>
0
[news] Redis extension 2.0.9 released Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/news/188/redis-extension-2-0-9-released https://www.yiiframework.com/news/188/redis-extension-2-0-9-released samdark samdark

We are very pleased to announce the release of Redis extension version 2.0.9 fixing zrangebyscore and adding >, <, >= and <= support to ActiveQuery.

See the CHANGELOG for details.

]]>
0
[news] Sphinx extension 2.0.11 released Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/news/187/sphinx-extension-2-0-11-released https://www.yiiframework.com/news/187/sphinx-extension-2-0-11-released samdark samdark

We are very pleased to announce the release of Sphinx extension version 2.0.11. In this release there is a bug fixed that yii\sphinx\ActiveQuery::all() was unable to follow instructions given by method indexBy().

See the CHANGELOG for details.

]]>
0
[news] Twig extension 2.2.1 released Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/news/186/twig-extension-2-2-1-released https://www.yiiframework.com/news/186/twig-extension-2-2-1-released samdark samdark

We are very pleased to announce the release of Twig extension version 2.2.1. This release fixes an error when outputting DateTime dates.

See the CHANGELOG for details.

]]>
0
[news] Swiftmailer extension 2.1.2 released Sun, 23 Sep 2018 22:04:27 +0000 https://www.yiiframework.com/news/185/swiftmailer-extension-2-1-2-released https://www.yiiframework.com/news/185/swiftmailer-extension-2-1-2-released samdark samdark

We are very pleased to announce the release of Swiftmailer extension version 2.1.2. This release brings automatic transport restart and adds an ability to specify the disposition of an attachment by supplying a setDisposition value when embedding content in a message.

See the CHANGELOG for details.

]]>
0
[news] HTTP client extension 2.0.7 released Sun, 23 Sep 2018 21:57:52 +0000 https://www.yiiframework.com/news/184/http-client-extension-2-0-7-released https://www.yiiframework.com/news/184/http-client-extension-2-0-7-released samdark samdark

We are very pleased to announce the release of HTTP client extension version 2.0.7. In this release, Response::detectFormatByContent was fixed to properly detect JSON Array. Additionally, Request::setFullUrl() method was added.

See the CHANGELOG for details.

]]>
0
[news] Debug extension 2.0.14 released Sun, 23 Sep 2018 22:38:01 +0000 https://www.yiiframework.com/news/183/debug-extension-2-0-14-released https://www.yiiframework.com/news/183/debug-extension-2-0-14-released samdark samdark

We are very pleased to announce the release of Debug extension version 2.0.14. In this release, additionally to bugfixes, there's new "Events" panel.

See the CHANGELOG for details.

]]>
0
[extension] onmotion/yii2-page-assessments Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/extension/onmotion/yii2-page-assessments https://www.yiiframework.com/extension/onmotion/yii2-page-assessments onmotion onmotion

Yii2 page assessment extension

  1. Installation
  2. Usage
  3. Options
  4. Events

The page assessment module for Yii2 framework based on Vue2.

Latest Stable Version Total Downloads Monthly Downloads License

Fluent view:

fluent

Static (embeded in a page) view:

fluent

Installation

Just run:

composer require onmotion/yii2-page-assessments

or add

"onmotion/yii2-page-assessments": "*"

to the require section of your composer.json file.

apply migration:

php yii migrate --migrationPath=@vendor/onmotion/yii2-page-assessments/migrations

Usage

You must add to your config:

'modules' => [
    //...
    'assessments' => [
        'class' => 'onmotion\assessments\Module',
    ],
    //...
],

Then you can use the widget somewhere on the page:

Fluent view example:

echo \onmotion\assessments\widget\AssessmentWidget::widget([
    'fluent' => false, // static or fluent view
    'questions' => [
        'Is this page helpful?', // simple question
        [
            'title' => 'What do you think about it?',
            'maxValue' => 6, 
            'allowComment' => true // allow optional comment
        ]
    ]
]);

Options

option type default description
fluent bool false fluent or static view
questions string || array see example
model (optional) ActiveRecord null Attach Model::class info with primary key

Events

assessment.show - when an assessment item appears.

document.addEventListener('assessment.show', function (e) {
    console.log(e.detail);
}, false);
]]>
0
[news] Auth Client extension 2.1.7 released Thu, 20 Sep 2018 07:26:26 +0000 https://www.yiiframework.com/news/182/auth-client-extension-2-1-7-released https://www.yiiframework.com/news/182/auth-client-extension-2-1-7-released samdark samdark

We are very pleased to announce the release of Auth Client extension version 2.1.7. It fixes OAuth2 client unsetting scope on defaultReturnUrl. Previously it was causing bad request from recent version of Google provider.

See the CHANGELOG for details.

]]>
0
[extension] mahkali/yii2-bsnvalidator Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/extension/mahkali/yii2-bsnvalidator https://www.yiiframework.com/extension/mahkali/yii2-bsnvalidator mahkali mahkali

yii2-bsnvalidator

  1. Installation
  2. Usage
  3. License

This extension provides BSN (Burger Service Nummer) validation for Yii Framework 2.0.

Installation

The preferred way to install this extension is through composer.

Either run

$ php composer.phar require mahkali/yii2-bsnvalidator "@dev"

or add

"mahkali/yii2-bsnvalidator": "@dev"

to the `require` section of your composer.json file.

Usage

BsnValidator
// add this in your model
use mahkali\validators\BsnValidator;

// use the validator in your model rules
public function rules() {
    return [
       	['bsn', BsnValidator::class],
    ];
}

License

yii2-bsnvalidator is released under the MIT License. See the bundled LICENSE.md for details.

]]>
0
[extension] hoaaah/yii2-universal-theme-asset Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/extension/hoaaah/yii2-universal-theme-asset https://www.yiiframework.com/extension/hoaaah/yii2-universal-theme-asset hoAAah hoAAah

YII2 Universal-Business & E-Commerce Template Assets Library

  1. Installation
  2. Usage
  3. Creator

This extensions is library for Universal-Business & E-Commerce Template Themes

Universal-Business is clean and stylish universal website template built with Bootstrap 3.3. It stands out with its clean design and elegant typography. It is one of the most complex free Bootstrap templates and with almost 30k downloads (as of Feb 2017), it is also my most popular Bootstrap freebie.

Start Bootstrap was created by and is maintained by DevCows

Installation

The preferred way to install this extension is through composer.

Either run

composer require hoaaah/yii2-universal-theme-asset:dev-master

or add

"hoaaah/yii2-universal-theme-asset": "*"

to the require section of your composer.json file.

Usage

You can use an example views in views-example and copy it to your view.

Don't forget to use this in your view

use hoaaah\universal\UniversalAsset;

UniversalAsset::register($this);

and just in case you want to use vendor image, to call any content of vendor image you can use this

$image = hoaaah\universal\UniversalAsset::register($this);

<img src=<?= $image->baseUrl.'/img/portfolio/startup-framework.png' ?> class="img-responsive" alt="">

it will call startup-framework.png from /vendor/hoaaah/yii2-universal-theme-asset/assets/img/portofolio/startup-framework.png

Creator

This Universal-Business library for Yii2 was created by and is maintained by Heru Arief Wijaya.

]]>
0
[extension] hoaaah/yii2-startbootstrap-stylish-portfolio Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/extension/hoaaah/yii2-startbootstrap-stylish-portfolio https://www.yiiframework.com/extension/hoaaah/yii2-startbootstrap-stylish-portfolio hoAAah hoAAah

yii2-startbootstrap-stylish-portfolio

  1. Installation
  2. Usage

This extensions is library for Startbootstrap Stylish-Portofolio Themes

Stylish Portfolio is a responsive, one page portfolio theme for Bootstrap created by Start Bootstrap. The theme features multiple content sections with an off canvas navigation menu.

Start Bootstrap was created by and is maintained by David Miller, Owner of Blackrock Digital.

Start Bootstrap is based on the Bootstrap framework created by Mark Otto and Jacob Thorton.

Installation

The preferred way to install this extension is through composer.

Either run

composer require hoaaah/yii2-startbootstrap-stylish-portfolio:dev-master

or add

"hoaaah/yii2-startbootstrap-stylish-portfolio": "*"

to the require section of your composer.json file.

Usage

Once the extension is installed, simply use it in your code by :

<?= \hoaaah\stylish\AutoloadExample::widget(); ?>```
]]>
0
[extension] hoaaah/yii2-newshop Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/extension/hoaaah/yii2-newshop https://www.yiiframework.com/extension/hoaaah/yii2-newshop hoAAah hoAAah

New Shop e-Commerce Template

  1. Installation
  2. Usage
  3. About Template

New Shop e-Commerce Template

Installation

The preferred way to install this extension is through composer.

Either run

php composer require hoaaah/yii2-newshop "dev-master"

or add

"hoaaah/yii2-newshop": "dev-master"

to the require section of your composer.json file.

Usage

Once the extension is installed, simply use it in your code by :

<?php
use hoaaah\Newshop\NewShopAsset;

NewShopAsset::register($this);
$directoryAsset = \hoaaah\Newshop\NewShopAsset::register($this);
?>
<img src="<?= $directoryAsset->baseUrl ?>/images/bag.png" alt="" />

About Template

New Shop Template are e-commerce template designed by W3Layouts licensed under Creative Commons Attribution 3.0 Unported

For more information about New Shop Template License read here

]]>
0
[extension] hoaaah/yii2-micro Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/extension/hoaaah/yii2-micro https://www.yiiframework.com/extension/hoaaah/yii2-micro hoAAah hoAAah

Yii2 MicroFramework Template

  1. Yii2 MicroFramework Template
  2. Installation
  3. Creator

Yii2 MicroFramework Template

This is a MicroFramework Template use Yii2. This Template build with this guide and you can modified it to use any of costumization.

Installation

The preferred way to install this CMS is through composer.

Either run

composer global require "fxp/composer-asset-plugin:^1.2.0"
composer create-project --prefer-dist hoaaah/yii2-micro [app_name]

Default database of this microframework use sqlite but you can modified it with your own database.

<?php
return [
    'components' => [
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=localhost;dbname=your_db_name',
            'username' => 'root',
            'password' => '',
            'charset' => 'utf8',
        ],
    ],
];

If you use your own db, then run migration to create table in selected database.

vendor/bin/yii migrate/up --appconfig=config.php

Creator

This Template was created by and is maintained by Heru Arief Wijaya.

]]>
0
[wiki] Update and Delete buttons on Breadcrumb Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/wiki/2544/update-and-delete-buttons-on-breadcrumb https://www.yiiframework.com/wiki/2544/update-and-delete-buttons-on-breadcrumb adinugro adinugro

The definition of breadcrumbs according to its documentation is as follow: Breadcrumbs displays a list of links indicating the position of the current page in the whole site hierarchy.

We can define the breadcrumbs easily by adding these lines.

$this->title = $model->formNo;
$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Supplier receiving'), 'url' => ['index', 'type' => $model->type]];
$this->params['breadcrumbs'][] = ['label' => $this->title, 'url' => ['view', 'id' => $model->id]];

Reading the documentation, I encountered the template keyword. I was excited about the possibility to add buttons into breadcrumbs. Add these lines and you would have buttons on the right side of the breadcrumb.

$this->title = $model->formNo;
$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Supplier receiving'), 'url' => ['index', 'type' => $model->type]];
$this->params['breadcrumbs'][] = ['label' => $this->title, 'url' => ['view', 'id' => $model->id]];
$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Delete'), 'template' =>
    Html::tag('span', Html::a(Html::icon('glyphicon glyphicon-trash white') . ' ' . Yii::t('app', 'Delete'), Url::to(['delete', 'id' => $model->id]), [
                'class' => 'btn btn-xs btn-danger',
                'title' => Yii::t('app', 'Delete'),
                'data-pjax' => '0',
                'data-method' => 'POST',
                'data-confirm' => Yii::t('app', 'Are you sure you want to delete this supplier receiving?'),
                    ]
            ), ['class' => 'pull-right'])];
$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Update'), 'template' => Html::tag('span', Html::a(
                    Html::icon('glyphicon glyphicon-pencil') . ' ' . Yii::t('app', 'Update'), Url::to(['update', 'id' => $model->id, 'inview' => 1]), [
                'class' => 'btn btn-xs btn-warning',
                'title' => Yii::t('app', 'Update'),
                'role' => 'modal-remote',
                'data-toggle' => 'tooltip',
                    ]
            ), ['class' => 'pull-right', 'style' => 'margin-right: 5px;'])];

Actually you can use this line to define the template, but $links means the full link. A suggestion to the developer is to make the $url and $label variables to be available like $links, so that we can make the template more flexible and meaningful than above codes.

FYI,

  1. I use ajaxcrud extension, so that the update link has 'role' => 'modal-remote' to allow the update process taken place on the modal window. I added a inview parameter to distinguish the update from index or view. Both actions will be called using ajax request and will show the form on the modal, but the index update will redirect to index and refresh gridview while in the view, it should redirect to the view.
  2. On the template, I used span over li to make ' / ' character not appear on the links buttons.

A simple tip to make the view layout efficient.

]]>
0
[extension] rohitiuc/yii2-dynamicform Tue, 25 Sep 2018 00:59:34 +0000 https://www.yiiframework.com/extension/rohitiuc/yii2-dynamicform https://www.yiiframework.com/extension/rohitiuc/yii2-dynamicform RohitIUC RohitIUC

yii2-dynamicform

  1. Installation
  2. Demos
  3. Usage

It is widget to yii2 framework to clone form elements in a nested manner, maintaining accessibility. yii2-dynamicform

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist rohitiuc/yii2-dynamicform "@dev"

or add

"rohitiuc/yii2-dynamicform": "@dev"

to the require section of your composer.json file.

Demos

Usage

Hypothetical Scenario

Database

The View
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use rohitiuc\dynamicform\DynamicFormWidget;
?>

<div class="customer-form">

    <?php $form = ActiveForm::begin(['id' => 'dynamic-form']); ?>
    <div class="row">
        <div class="col-sm-6">
            <?= $form->field($modelCustomer, 'first_name')->textInput(['maxlength' => true]) ?>
        </div>
        <div class="col-sm-6">
            <?= $form->field($modelCustomer, 'last_name')->textInput(['maxlength' => true]) ?>
        </div>
    </div>

    <div class="panel panel-default">
        <div class="panel-heading"><h4><i class="glyphicon glyphicon-envelope"></i> Addresses</h4></div>
        <div class="panel-body">
             <?php DynamicFormWidget::begin([
                'widgetContainer' => 'dynamicform_wrapper', // required: only alphanumeric characters plus "_" [A-Za-z0-9_]
                'widgetBody' => '.container-items', // required: css class selector
                'widgetItem' => '.item', // required: css class
                'limit' => 4, // the maximum times, an element can be cloned (default 999)
                'min' => 1, // 0 or 1 (default 1)
                'insertButton' => '.add-item', // css class
                'deleteButton' => '.remove-item', // css class
                'model' => $modelsAddress[0],
                'formId' => 'dynamic-form',
                'formFields' => [
                    'full_name',
                    'address_line1',
                    'address_line2',
                    'city',
                    'state',
                    'postal_code',
                ],
            ]); ?>

            <div class="container-items"><!-- widgetContainer -->
            <?php foreach ($modelsAddress as $i => $modelAddress): ?>
                <div class="item panel panel-default"><!-- widgetBody -->
                    <div class="panel-heading">
                        <h3 class="panel-title pull-left">Address</h3>
                        <div class="pull-right">
                            <button type="button" class="add-item btn btn-success btn-xs"><i class="glyphicon glyphicon-plus"></i></button>
                            <button type="button" class="remove-item btn btn-danger btn-xs"><i class="glyphicon glyphicon-minus"></i></button>
                        </div>
                        <div class="clearfix"></div>
                    </div>
                    <div class="panel-body">
                        <?php
                            // necessary for update action.
                            if (! $modelAddress->isNewRecord) {
                                echo Html::activeHiddenInput($modelAddress, "[{$i}]id");
                            }
                        ?>
                        <?= $form->field($modelAddress, "[{$i}]full_name")->textInput(['maxlength' => true]) ?>
                        <div class="row">
                            <div class="col-sm-6">
                                <?= $form->field($modelAddress, "[{$i}]address_line1")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-6">
                                <?= $form->field($modelAddress, "[{$i}]address_line2")->textInput(['maxlength' => true]) ?>
                            </div>
                        </div><!-- .row -->
                        <div class="row">
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]city")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]state")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]postal_code")->textInput(['maxlength' => true]) ?>
                            </div>
                        </div><!-- .row -->
                    </div>
                </div>
            <?php endforeach; ?>
            </div>
            <?php DynamicFormWidget::end(); ?>
        </div>
    </div>

    <div class="form-group">
        <?= Html::submitButton($modelAddress->isNewRecord ? 'Create' : 'Update', ['class' => 'btn btn-primary']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>
Javascript Events

$(".dynamicform_wrapper").on("beforeInsert", function(e, item) {
    console.log("beforeInsert");
});

$(".dynamicform_wrapper").on("afterInsert", function(e, item) {
    console.log("afterInsert");
});

$(".dynamicform_wrapper").on("beforeDelete", function(e, item) {
    if (! confirm("Are you sure you want to delete this item?")) {
        return false;
    }
    return true;
});

$(".dynamicform_wrapper").on("afterDelete", function(e) {
    console.log("Deleted item!");
});

$(".dynamicform_wrapper").on("limitReached", function(e, item) {
    alert("Limit reached");
});

The Controller (sample code)
<?php

namespace app\controllers;

use Yii;
use app\models\Customer;
use app\models\CustomerSearch;
use app\models\Address;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use app\base\Model;
use yii\web\Response;
use yii\widgets\ActiveForm;
use yii\helpers\ArrayHelper;

/**
 * CustomerController implements the CRUD actions for Customer model.
 */
class CustomerController extends Controller
{
    ...

    /**
     * Creates a new Customer model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate()
    {
        $modelCustomer = new Customer;
        $modelsAddress = [new Address];
        if ($modelCustomer->load(Yii::$app->request->post())) {

            $modelsAddress = Model::createMultiple(Address::classname());
            Model::loadMultiple($modelsAddress, Yii::$app->request->post());

            // ajax validation
            if (Yii::$app->request->isAjax) {
                Yii::$app->response->format = Response::FORMAT_JSON;
                return ArrayHelper::merge(
                    ActiveForm::validateMultiple($modelsAddress),
                    ActiveForm::validate($modelCustomer)
                );
            }

            // validate all models
            $valid = $modelCustomer->validate();
            $valid = Model::validateMultiple($modelsAddress) && $valid;
            
            if ($valid) {
                $transaction = \Yii::$app->db->beginTransaction();
                try {
                    if ($flag = $modelCustomer->save(false)) {
                        foreach ($modelsAddress as $modelAddress) {
                            $modelAddress->customer_id = $modelCustomer->id;
                            if (! ($flag = $modelAddress->save(false))) {
                                $transaction->rollBack();
                                break;
                            }
                        }
                    }
                    if ($flag) {
                        $transaction->commit();
                        return $this->redirect(['view', 'id' => $modelCustomer->id]);
                    }
                } catch (Exception $e) {
                    $transaction->rollBack();
                }
            }
        }

        return $this->render('create', [
            'modelCustomer' => $modelCustomer,
            'modelsAddress' => (empty($modelsAddress)) ? [new Address] : $modelsAddress
        ]);
    }

    /**
     * Updates an existing Customer model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
     */
    public function actionUpdate($id)
    {
        $modelCustomer = $this->findModel($id);
        $modelsAddress = $modelCustomer->addresses;

        if ($modelCustomer->load(Yii::$app->request->post())) {

            $oldIDs = ArrayHelper::map($modelsAddress, 'id', 'id');
            $modelsAddress = Model::createMultiple(Address::classname(), $modelsAddress);
            Model::loadMultiple($modelsAddress, Yii::$app->request->post());
            $deletedIDs = array_diff($oldIDs, array_filter(ArrayHelper::map($modelsAddress, 'id', 'id')));

            // ajax validation
            if (Yii::$app->request->isAjax) {
                Yii::$app->response->format = Response::FORMAT_JSON;
                return ArrayHelper::merge(
                    ActiveForm::validateMultiple($modelsAddress),
                    ActiveForm::validate($modelCustomer)
                );
            }

            // validate all models
            $valid = $modelCustomer->validate();
            $valid = Model::validateMultiple($modelsAddress) && $valid;

            if ($valid) {
                $transaction = \Yii::$app->db->beginTransaction();
                try {
                    if ($flag = $modelCustomer->save(false)) {
                        if (! empty($deletedIDs)) {
                            Address::deleteAll(['id' => $deletedIDs]);
                        }
                        foreach ($modelsAddress as $modelAddress) {
                            $modelAddress->customer_id = $modelCustomer->id;
                            if (! ($flag = $modelAddress->save(false))) {
                                $transaction->rollBack();
                                break;
                            }
                        }
                    }
                    if ($flag) {
                        $transaction->commit();
                        return $this->redirect(['view', 'id' => $modelCustomer->id]);
                    }
                } catch (Exception $e) {
                    $transaction->rollBack();
                }
            }
        }

        return $this->render('update', [
            'modelCustomer' => $modelCustomer,
            'modelsAddress' => (empty($modelsAddress)) ? [new Address] : $modelsAddress
        ]);
    }

    ...
}
Model Class
<?php

namespace app\base;

use Yii;
use yii\helpers\ArrayHelper;

class Model extends \yii\base\Model
{
    /**
     * Creates and populates a set of models.
     *
     * @param string $modelClass
     * @param array $multipleModels
     * @return array
     */
    public static function createMultiple($modelClass, $multipleModels = [])
    {
        $model    = new $modelClass;
        $formName = $model->formName();
        $post     = Yii::$app->request->post($formName);
        $models   = [];

        if (! empty($multipleModels)) {
            $keys = array_keys(ArrayHelper::map($multipleModels, 'id', 'id'));
            $multipleModels = array_combine($keys, $multipleModels);
        }

        if ($post && is_array($post)) {
            foreach ($post as $i => $item) {
                if (isset($item['id']) && !empty($item['id']) && isset($multipleModels[$item['id']])) {
                    $models[] = $multipleModels[$item['id']];
                } else {
                    $models[] = new $modelClass;
                }
            }
        }

        unset($model, $formName, $post);

        return $models;
    }
}


To zero or more elements (use the following code in your view file)

<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use rohitiuc\dynamicform\DynamicFormWidget;
?>

<div class="customer-form">

    <?php $form = ActiveForm::begin(['id' => 'dynamic-form']); ?>
    <div class="row">
        <div class="col-sm-6">
            <?= $form->field($modelCustomer, 'first_name')->textInput(['maxlength' => true]) ?>
        </div>
        <div class="col-sm-6">
            <?= $form->field($modelCustomer, 'last_name')->textInput(['maxlength' => true]) ?>
        </div>
    </div>

    <?php DynamicFormWidget::begin([
        'widgetContainer' => 'dynamicform_wrapper', // required: only alphanumeric characters plus "_" [A-Za-z0-9_]
        'widgetBody' => '.container-items', // required: css class selector
        'widgetItem' => '.item', // required: css class
        'limit' => 4, // the maximum times, an element can be added (default 999)
        'min' => 0, // 0 or 1 (default 1)
        'insertButton' => '.add-item', // css class
        'deleteButton' => '.remove-item', // css class
        'model' => $modelsAddress[0],
        'formId' => 'dynamic-form',
        'formFields' => [
            'full_name',
            'address_line1',
            'address_line2',
            'city',
            'state',
            'postal_code',
        ],
    ]); ?>

    <div class="panel panel-default">
        <div class="panel-heading">
            <h4>
                <i class="glyphicon glyphicon-envelope"></i> Addresses
                <button type="button" class="add-item btn btn-success btn-sm pull-right"><i class="glyphicon glyphicon-plus"></i> Add</button>
            </h4>
        </div>
        <div class="panel-body">
            <div class="container-items"><!-- widgetBody -->
            <?php foreach ($modelsAddress as $i => $modelAddress): ?>
                <div class="item panel panel-default"><!-- widgetItem -->
                    <div class="panel-heading">
                        <h3 class="panel-title pull-left">Address</h3>
                        <div class="pull-right">
                            <button type="button" class="remove-item btn btn-danger btn-xs"><i class="glyphicon glyphicon-minus"></i></button>
                        </div>
                        <div class="clearfix"></div>
                    </div>
                    <div class="panel-body">
                        <?php
                            // necessary for update action.
                            if (! $modelAddress->isNewRecord) {
                                echo Html::activeHiddenInput($modelAddress, "[{$i}]id");
                            }
                        ?>
                        <?= $form->field($modelAddress, "[{$i}]full_name")->textInput(['maxlength' => true]) ?>
                        <div class="row">
                            <div class="col-sm-6">
                                <?= $form->field($modelAddress, "[{$i}]address_line1")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-6">
                                <?= $form->field($modelAddress, "[{$i}]address_line2")->textInput(['maxlength' => true]) ?>
                            </div>
                        </div><!-- .row -->
                        <div class="row">
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]city")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]state")->textInput(['maxlength' => true]) ?>
                            </div>
                            <div class="col-sm-4">
                                <?= $form->field($modelAddress, "[{$i}]postal_code")->textInput(['maxlength' => true]) ?>
                            </div>
                        </div><!-- .row -->
                    </div>
                </div>
            <?php endforeach; ?>
            </div>
        </div>
    </div><!-- .panel -->
    <?php DynamicFormWidget::end(); ?>

    <div class="form-group">
        <?= Html::submitButton($modelAddress->isNewRecord ? 'Create' : 'Update', ['class' => 'btn btn-primary']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>
]]>
0
[extension] urosg/yii2-outdated-browser-rework Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/extension/urosg/yii2-outdated-browser-rework https://www.yiiframework.com/extension/urosg/yii2-outdated-browser-rework urosg80 urosg80

yii2-outdatedbrowser-rework

  1. About
  2. Installation
  3. Usage
  4. License

YII2 Widget implementing outdated-browser-rework package for browser better detection

About

This widget was inspired by the mdscomp/yii2-outdated-browser-widget which uses the Outdated Browser script by Bürocratik.

This widget on the other hand uses the Outdated Browser Rework script made by the Mike MacCana.

Installation

The preferred way to install this extension is through composer. Check the composer.json for this extension's requirements and dependencies. Read this web tip /wiki on setting the minimum-stability settings for your application's composer.json.

To install, either run $ php composer.phar require urosg/yii2-outdated-browser-rework "~1.0" or add "urosg/yii2-outdated-browser-rework": "~1.0" to the require section of your composer.json file.

Refer to the CHANGELOG for details of release changes.

Usage

use urosg\widget\OutdatedBrowserRework;

// To use default configuration
echo OutdatedBrowserRework::widget();

// To specify custom configuration - listed are default settings
echo OutdatedBrowserReword::widget([
    'requiredCssProperty' => '',
    'language' => 'en',
    'isUnknownBrowserOK' => false,
    'requireChromeOnAndroid' => false,
    'messages' => [
        'outOfDate' => 'Your browser is out of date!',
        'updateWeb' => 'Update your browser to view this website correctly.',
        'updateGooglePlay' => 'Please install Chrome from Google Play',
        'updateAppStore' => 'Please update iOS from the Settings',
        'webUpdateUrl' => 'http://outdatedbrowser.com',
        'callToAction' => 'Update my browser now',
        'close' => 'Close'
    ],
    'browserSupport' => [
        'Chrome' => 57,
        'Edge' => 39,
        'Safari' => 10,
        'MobileSafari' => 10,
        'Firefox' => 50,
        'Opera' => 50,
        'Vivaldi' => 1,
        'IE' => false
    ]
]);

License

yii2-outdated-browser-rework is released under the BSD-3 Clause license. See the bundled LICENSE file for details.

]]>
0
[extension] Mirocow/yii2-elasticsearch Thu, 13 Sep 2018 23:18:53 +0000 https://www.yiiframework.com/extension/Mirocow/yii2-elasticsearch https://www.yiiframework.com/extension/Mirocow/yii2-elasticsearch Mirocow Mirocow

Elasticsearch module based on official Elasticsearch PHP library

Join the chat at https://gitter.im/Mirocow/yii2-elasticsearch

Docs are available in english and russian.

Install

$ composer require --prefer-dist mirocow/yii2-elasticsearch

Configure

  • Create a class that implements the common\modules\elasticsearch\contracts\Index interface.
  • Add it to the module configuration in common/config/main.php
  • Start indexing
return [
    'modules' => [

        // elasticsearch
        common\modules\elasticsearch\Module::MODULE_NAME => [
          'class' => common\modules\elasticsearch\Module::class,
          'indexes' => [
            common\repositories\indexes\ProductsSearchIndex::class
          ]
        ],

    ],
    'bootstrap' => [
        common\modules\elasticsearch\Bootstrap::class
    ]
];

Create index

Create empty index `bash $ php yii elasticsearch/index/create index_name `

Fill index with all documents `bash $ php yii elasticsearch/index/populate index_name `

Destroy an index and all its data `bash $ php yii elasticsearch/index/destroy index_name `

Remove all existing indexes, re-create all indexes and re-index all documents for all indexes `bash $ php yii elasticsearch/index/rebuild `

Debug

$ export PHP_IDE_CONFIG="serverName=www.site.loc" && export XDEBUG_CONFIG="remote_host=192.168.1.6 idekey=xdebug" && php7.0 ./yii elasticsearch/index/create products_search

Query

For creating queries, you may use https://github.com/crowdskout/es-search-builder

]]>
0
[extension] lubosdz/yii2-ui-range-plus-minus Fri, 14 Sep 2018 08:05:18 +0000 https://www.yiiframework.com/extension/lubosdz/yii2-ui-range-plus-minus https://www.yiiframework.com/extension/lubosdz/yii2-ui-range-plus-minus lubosdz lubosdz

Yii2 Input widget for numbers with plus - minus handles

Widget for framework Yii2 which enables to take user numeric input (integer, decimals) and increase/decrease the value by configured step, optionally within the min - max range.

Screenshot

Installation

$ composer require "lubosdz/yii2-ui-range-plus-minus" : "~1.0.0"

Usage


use lubosdz\ui\RangePlusMinus;

<?= $form->field($model, 'area_m2')->widget(RangePlusMinus::className(), [
	'unit' => 'm2',
	'min' => 10,
	'max' => 100,
	'tooHigh' => Yii::t('app', 'Maximum value is {max}.'),
	'tooLow' => Yii::t('app', 'Minimum value is {min}.'),
	'step' => 5,
	'cssClassMinus' => 'fa fa-minus',
	'cssClassPlus' => 'fa fa-plus',
	'options' => [
		'onchange' => new JsExpression('console.log(this)'),
	],
]) ?>

<?= RangePlusMinus::widget([
	'model' => $model,
	'attribute' => 'frequency',
	'unit' => 'MHz',
	'min' => 10,
	'max' => 100,
	'decimals' => 3,
	'step' => 0.05,
	'cssMinusButton' => 'btn btn-default',
	'cssMinusIcon' => 'glyphicon glyphicon-chevron-down',
	'cssPlusButton' => 'btn btn-default',
	'cssPlusIcon' => 'glyphicon glyphicon-chevron-up',
]) ?>

Widget options

Option Description
unit Measure unit, e.g. kg, MHz
cssWrapper CSS class to set field width within a row, defaults to col-md-6
thousandSep Thousands separator, defaults to empty string
decimalsSep Decimals separator, defaults to comma .
min Minimum allowed value
max Maximum allowed value
step Value increased or decreased by this value, defaults to 1.
defaultValue The value set on first load
tooHigh Error message to show when the new value is higher than max value
tooLow Error message to show when the new value is lower than min value
decimals How many decimals should be value formatted to, default 0
roundPrecision How should be value rounded, e.g. 100 will round to hundreds, 1000 will round the value to thousands etc, default 0
css Any custom CSS string
cssMinusIcon CSS class for the minus icon, defaults to glyphicon glyphicon-minus
cssMinusButton CSS class for the minus button, sets the background color, defaults to btn btn-success (green button)
cssPlusIcon CSS class for the plus icon, defaults to glyphicon glyphicon-plus
cssPlusButton CSS class for the plus button, sets the background color, defaults to btn btn-danger (red button)

License

This extension is open source and licensed under BSD-3-Clause (same as Yii2 framework).

]]>
0
[extension] mludvik/yii2-gopay Sun, 09 Sep 2018 08:47:51 +0000 https://www.yiiframework.com/extension/mludvik/yii2-gopay https://www.yiiframework.com/extension/mludvik/yii2-gopay speculatius speculatius

yii2-gopay

  1. Installation
  2. Usage
  3. Example

Yii2 integration for official GoPay's PHP SDK for Payments REST API.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require mludvik/yii2-gopay:"~1.0"

or add

"mludvik/yii2-gopay": "~1.0"

to the require section of your composer.json.

Usage

Before you start using this extension, it is recommended to read GoPay REST API documentation.

GoPayComponent

GoPayComponent is thin wrapper over GoPay PHP SDK.

Enable it by adding respective component configuration.

'components' => [

  ...

  'goPay' => [
    'class' => 'mludvik\gopay\GoPayComponent',
    'config' => [
      'goid' => '...',
      'clientId' => '...',
      'clientSecret' => '...',
      'isProductionMode' => YII_ENV_PROD,
      'scope' => TokenScope::ALL,
      'language' => Language::ENGLISH,
      'timeout' => 30,
    ],
  ],

  ...
]

Then you can call any method you would call on Payments object.

use Yii;

Yii::$app->goPay->createPayment([...]);
Yii::$app->goPay->getStatus(...);
...
GoPayAsset

GoPayAsset imports front-end GoPay dependencies to your pages. It is sensitive to YII_EVN constant — loads production version when YII_ENV === 'prod', test version otherwise. There are multiple ways how to use it.

  1. To load it on all pages, register it in AppAsset.
class AppAsset extends AssetBundle {

  ...

  public $depends = [
    ...
    'mludvik\gopay\GoPayAsset',
  ];
}
  1. To load it on specific page, register it in respective view.
use mludvik\gopay\GoPayAsset;

GoPayAsset::register($this);
  1. When using GoPayForm described below, you do not need to register GoPayAsset at all. It will be registered automatically on pages where GoPayForm is rendered.
GoPayForm

GoPayForm is widget created to help you build checkout page. Use it if you like or develop your own widget with the help of GoPayComponent and GoPayAsset.

GoPayForm is basically ActiveForm with 2 differences.

  • It uses asynchronous POST request to submit data to controller and then redirects user to payment gateway.
  • It has static method response, which can be used in controller to build expected response to form submission.

Example

First of all, you will need form to collect user payment preferences (eg. preferred payment method). It is also a good place to put some business logic in.

namespace app\models;

use Yii;
use yii\base\Model;

class CheckoutForm extends Model {

  public $paymentMethod;

  ...

  public function createPayment() {
    // Build request based on form's data.
    $request = [...];

    // Establish payment on GoPay side.
    return Yii::$app->goPay->createPayment($request);
  }
}

Then create checkout action.

namespace app\controllers;

use Yii;
use yii\web\Controller;
use mludvik\gopay\GoPayForm;
use app\models\CheckoutForm;

class PaymentController extends Controller {

  ...

  public function actionCheckout() {
    $model = CheckoutForm;

    if(Yii::$app->request->isAjax) {
      if($model->load(Yii::$app->request->post()) && $model->validate()) {
        $response = $model->createPayment();
        return GoPayForm::response($response);
      } else {
        return GoPayForm::response(null);
      }
    }

    return $this->render('checkout', ['model' => $model]);
  }
}

Finally, create the view.

<?php use mludvik\gopay\GoPayForm; ?>

<?php $form = GoPayForm::begin(); ?>

  ...

  <?= Html::submitButton('Pay') ?>
<?php GoPayForm::end(); ?>
]]>
0
[extension] marketflow/yii2-regex-validator Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/extension/marketflow/yii2-regex-validator https://www.yiiframework.com/extension/marketflow/yii2-regex-validator sammousa sammousa

yii2-regex-validator

Validate regular expressions with Yii2

This validator validates if a given regular expression is a valid regular expression. It does this by trying to match a subject and catching any exceptions.

It does not (yet) support client side validation since Javascript and PHP have different RE syntaxes.

]]>
0
[extension] sam-it/yii2-magic Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/extension/sam-it/yii2-magic https://www.yiiframework.com/extension/sam-it/yii2-magic sammousa sammousa

Latest Stable Version Total Downloads Latest Unstable Version License Monthly Downloads Daily Downloads

yii2-magic

Improvements for Yii2 that make it more "magic".

ActionInjectionTrait

Use this trait in your controller to get dependency injection in controller actions. use \SamIT\Yii2\Traits\ActionInjectionTrait;

HighlightUnsafeAttributesTrait

Use this trait in your form to highlight unsafe attributes. use \SamIT\Yii2\Traits\HighlightUnsafeAttributesTrait;

SingleTableInheritanceTrait

Use this trait in your active record model to implement single table inheritance. `` use \SamIT\Yii2\Traits\SingleTableInheritanceTrait;

protected static function inheritanceConfig() {

return [
    'map' => [
        PartnerProject::class => 'partner'
    ],
    'column' => 'type'
];

} ` This trait uses a different query object. If you use your own ActiveQuery implementation, use SingleTableInheritanceQueryTrait`.

]]>
0
[extension] sam-it/yii2-jsonbehavior Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/extension/sam-it/yii2-jsonbehavior https://www.yiiframework.com/extension/sam-it/yii2-jsonbehavior sammousa sammousa

Scrutinizer Code Quality Code Coverage Build Status Total Downloads Latest Stable Version

Yii2 JsonBehavior

Work with JSON fields in Yii2

This behavior adds advanced support for working with JSON data in Yii AR models.

Use JSON fields like normal fields

Consider a model having a data attribute that is stored as JSON. `` public function behaviors() {

return [
    ['class' => JsonBehavior::class, 'jsonAttributes' => ['data']]
];

}

// Examples: $model = new Model(); $model->a = "test"; // If attribute 'a' does not exist this is stored inside the data.

$model->a['b'] = 'c']; // Nested arrays are supported.

$model->data = ['x' => 'y']; // Assigning directly is supported. ``

]]>
0
[extension] sam-it/yii2-csv-formatter Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/extension/sam-it/yii2-csv-formatter https://www.yiiframework.com/extension/sam-it/yii2-csv-formatter sammousa sammousa

yii2-csv-formatter

Yii2 CSV Response Formatter

]]>
0
[extension] sam-it/yii2-static-assets Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/extension/sam-it/yii2-static-assets https://www.yiiframework.com/extension/sam-it/yii2-static-assets sammousa sammousa

yii2-static-assets

Prevent publishing of assets at production time without changing your application.

Motivation

Nowadays docker is getting more and more attention and PHP applications are seeing different deployment scenarios. Where a few years ago if you split your nodes up at all you'd only split up the database server and the webserver that runs PHP as module or more recently via PHP-FPM, nowadays you want to split everything up.

Challenges

Having your webserver, for example nginx, running on a different server than PHP-FPM comes with several challenges, pros and cons:

  1. PHP can't write files and create publicly accessible URLs for them
  2. Cannot use local session storage
  3. File uploads that need to be publicly accessible need to be published to the webserver.
  4. File uploads that need to be protected have to accessible by all PHP nodes (so some kind of central storage is needed).

Solution

This extension will provide a solution for number 1 when it comes to Yii assets. The asset management system is nice when pushing changed assets directly to a server, it doesn't really work well in distributed environments though, so we need another approach.

This extension provides:

  • A console command that will scan your source code and vendor directory and will extract all your assets.
  • An AssetManager for use in production that will generate URLs for assets without checking for touching storage.

The workflow then becomes a bit different. During development the asset manager will act like a normal asset manager, publishing assets to the asset directory. When using docker-compose for the test environment you would mount the same host directory to the asset folder in the PHP container and in the webserver container.

During deployment the assetmanager simply returns URLs for assets on the assumption that they exist. Before deploying a new version of your app, you will rebuild your webserver container. This extension provides a console command that will publish all your assets to a directory of your choosing, this can then be used as part of the docker build context.

To publish your assets run the following command: yii staticAssets/assets/publish build12345

This will create the directory build12345 inside your runtime directory and publish all assets there.

Asset discovery / publishing

Assets are discovered by recursively iterating over all folders and files. Each file that ends with .php is then processed:

  • The namespace is extracted via regular expression matching.
  • The class name is extracted via regular expression matching.
  • We use reflection to check if the class is an instance of yii\web\AssetBundle and if so it is published.

Container building

To build an nignx container for server your application use this: yii staticAssets/assets/build-container You can configure the module to set some default values.

Configuration

For simple configuration use the ReadOnlyAssetManager in your application during production and development. This asset manager will use a simpler "hash" function that keeps directory structure readable. It supports $assetDevelopmentMode which allows for local asset development in a dockerized environment.

Asset development

The assumption is that you use docker-compose for local development, in which case you need to define a volume where assets are stored so that they are available in both the webserver as well as the phpfpm container: `` volumes: assets: nginx:

image: [name of your nginx container, built by this module]
environment:
  PHPFPM: "phpfpm:9000"
  RESOLVER: "127.0.0.11"
ports:
  - "12346:80" # Port where the application will be available
depends_on:
  - phpfpm
volumes:
# Defines the named volume as read-only for the webserver.
# Note the dev-assets, which allows to easily identify development
# mode while using browsers' developer tools.
  - type: volume
    source: assets
    target: /www/dev-assets
    read_only: true
    volume:
      nocopy: true

phpfpm:

dns: 8.8.4.4
image: [ name of your PHPFPM docker image ]
environment:
  DB_USER: root
  DB_NAME: test
  DB_PASS: secret
  DB_HOST: mysql
depends_on:
  - mysql
volumes:
  # The source code is loaded into PHPFPM for local development,
  # for production it should be baked into the image.
  - .:/project:ro
  # The asset volume, note the location which is where the ReadOnlyAssetManager
  # will publish assets when in development mode.
  - type: volume
    source: assets
    target: /tmp/assets



]]>
0
[extension] sam-it/yii2-phpfpm Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/extension/sam-it/yii2-phpfpm https://www.yiiframework.com/extension/sam-it/yii2-phpfpm sammousa sammousa

Build Status Code Coverage Scrutinizer Code Quality

yii2-phpfpm

Run Yii2 on PHP-FPM

]]>
0
[extension] sam-it/yii2-urlsigner Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/extension/sam-it/yii2-urlsigner https://www.yiiframework.com/extension/sam-it/yii2-urlsigner sammousa sammousa

Scrutinizer Code Quality Code Coverage Build Status

yii2-urlsigner Secure URL signing and validation.

The goal of this component is to enable stateless but secure URL validation. This can be useful, for example, when doing email validation or password reset.

The idea is simple, consider I want to change my email, the system could send me a link like this:

Of course, this is very insecure, and no one actually (hopefully) does it like this. One solution is to generate a random token:

This is secure, but requires keeping state on the server. This package solves the problem by signing the URL.

This allows us to verify that the URL was actually created by us therefore can be trusted.

Example


class RequestResetAction {

    public function run(
        UrlSigner $urlSigner,
        int $id,
        string $email
    ) {
        $user = User::find()->andWhere([
            'id' => $id,
            'email' => $email
        ]);

        $route = [
            '/user/do-reset',
            'id' => $user->id,
            'crc' => crc32($user->password_hash),
        ];

        /**
         * Sign the params.
         * 1st param is passed by reference, the component adds the params needed for HMAC.
         * 2nd param indicates that the params must match exactly, the user cannot add another param.
         * 3rd param sets the expiration to 1 hour
         **/
        $urlSigner->signParams($route, false, (new DateTime())->add(new DateInterval('PT1H')));

        $user->sendPasswordReset($route);



    }
}

class DoResetAction {

    public function behaviors()
    {
        return [
            'hmacFilter' => [
            'class' => HmacFilter::class,
            'signer' => $this->controller->module->get('urlSigner'),
        ];

    }
    public function run(
        int $id
    ) {
        // Here we can trust that the user got here through the link that we sent.



    }
}

Do not share secrets across hosts

If you use this component in a multi-host application you must make sure each host uses a different secret. The URL signing takes into account the absolute route and all given parameters, anything else is excluded from the signature and from validation. This means that if you have a structure like this:

And they use the same route, for example /user/do-reset, for password resets, a normal user will be able to change the domain without invalidating the signature.

]]>
0
[extension] sam-it/abac Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/extension/sam-it/abac https://www.yiiframework.com/extension/sam-it/abac sammousa sammousa

PHP Attribute Based Access Control

A simple framework for implementing ABAC in your application.

Yii2 Connector.

The Yii2 connector allows storing the permissions in a Yii2 ActiveRecord model. Configuration: `` 'components' => [

'abac' => [

    'class' => \SamIT\ABAC\connectors\yii2\Manager::class,
    'ruleDirectory' => __DIR__ . '/../rules';

'user' => [
    'accessChecker' => 'abac'
]

# Infinite loops.
Currently there is no pro
]]>
0
[news] Auth Client extension 2.1.6 released Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/news/181/auth-client-extension-2-1-6-released https://www.yiiframework.com/news/181/auth-client-extension-2-1-6-released samdark samdark

We are very pleased to announce the release of Auth Client extension version 2.1.6. It upgrades VKontakte API used to version 5.0 and fixes a couple of bugs related to OpenID and canceling login in auth form.

See the CHANGELOG for details.

]]>
0
[news] Replacing the forum software, moving to Discourse Mon, 03 Sep 2018 15:47:12 +0000 https://www.yiiframework.com/news/180/replacing-the-forum-software-moving-to-discourse https://www.yiiframework.com/news/180/replacing-the-forum-software-moving-to-discourse CeBe CeBe

A few month ago we have replaced the old Yii Framework website with a rewritten version in Yii 2. While developing the new site, we also discussed the replacement of the old IPB forum software with a more modern solution, but replacing the forum together with the site would have been too much work to do at once.

From a long discussion, which started already a few years ago, we have now evaluated different forum software and decided to go with Discourse, which is an open source forum software made by the people who created also StackOverflow. We are going to replace the old forum with a Discourse instance starting tomorrow (September 4, 2018).

Here is a list of things that are going to change:

  • User accounts will be managed by the website, there is no duplicate login as we have it now, and all users are signed in to the forum via SSO.
  • Forum categories, topics and posts are migrated from the old forum, so no content will be lost (we might re-arrange the categories though).
  • Links from the old forum should all be redirected to the new location. If you hit broken links, please report those to us!
  • Watched topics and watched forums are not going to be migrated, so if you want to get notified about new posts, make sure to visit the new forum and configure your notification settings as well as update watched topics.
  • User badges on the website do not include the forum posts anymore, instead we are using the Badge system by Discourse, which has a lot more badges than we had before.
  • Discourse allows you to configure it to behave like a mailing list, so if you prefer to take part in Yii discussions from your email client, you can do that now.

In case you have problems logging in to the new forum, please use the Contact form or Chat to get help.

There is a forum topic for discussion on this announcement.

]]>
0
[news] New member joining Yii team as primary Yii 3.0 developer Fri, 31 Aug 2018 22:23:17 +0000 https://www.yiiframework.com/news/179/new-member-joining-yii-team-as-primary-yii-3-0-developer https://www.yiiframework.com/news/179/new-member-joining-yii-team-as-primary-yii-3-0-developer samdark samdark

Andrii Vasyliev, @hiqsol joined Yii team. Andrii uses Yii daily for his team projects and is very interested in framework moving forward.

He's from Kiev, Ukraine and is part of HiQDev team same as another long term Yii team member, Dmytro Naumenko (@SilverFire).

His primary focus will be refreshing Yii architecture splitting it into more packages to achieve more frequent independent releases and making Yii core more robust.

]]>
0
[wiki] When to use Active Record Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/wiki/2541/when-to-use-active-record https://www.yiiframework.com/wiki/2541/when-to-use-active-record samdark samdark

When to use Active Record is a common question among developers, Yii and overall.

I have about 500K records in my DB tables and each query there are 2 or 3 joins. I was getting data via AR, about a hundred records a time and noticed that using createCommand consumes less memory and CPU. I think with DAO instead of AR it will be faster.

It is true that Active Record consumes memory for storing objects and CPU cycles for instantiate these objects.

Is AR bad? It it for small projects only? We have lots of inserts, about 5000 records an hour and we're using AR for that. Should we re-write?

AR is a pleasure to use when you're managing not that many records at the same time. CRUD is very easy with it. Yii 2 dirty attribute support (only what was modified is saved) off-loads database and mitigates many parallel editing conflicts. If you don't have complex logic in your app and you don't need entity abstractions, AR is an ideal choice.

AR is OK for queries not too complicated when they return no more than a hundred objects. Yes, it is faster and less memory consuming to use query builder or asArray() but working with arrays is significantly less convenient.

For complex queries, such as aggregates or reports, AR isn't recommended. These are easier to express with query builder or SQL. Same goes for import and export routines.

]]>
0
[wiki] Getting information from the current locale Thu, 09 Aug 2018 18:56:33 +0000 https://www.yiiframework.com/wiki/2540/getting-information-from-the-current-locale https://www.yiiframework.com/wiki/2540/getting-information-from-the-current-locale CeBe CeBe

Yii 2.0 comes with a formatter component to format dates, numbers, and other values for international users according to their locale. This is very useful for displaying data. When working with incoming data or when using enhanced input methods like the MaskedInput widget you sometimes need to access the symbols used by the formatter to generate a pattern or parse the input.

The Yii formatter does not have methods to access this data, it relies on the PHP intl extension for formatting. If you want to access the formatting symbols you need to work with intl directly.

Getting decimal and thousand separator

$locale = 'de_DE';

$formatter = new \NumberFormatter($locale,\NumberFormatter::DECIMAL);

$decimalSeparator = $formatter->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL);
$thousandSeparator = $formatter->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL);

There are more symbols than shown above, for the full list of symbols see the list of NumberFormatter constants in the php manual.

Getting a currency symbol

Getting the currency symbol is a bit more complicated if you do not want the symbol of the default currency of a locale, but another currency:

$locale = 'de_DE'; // get the currency symbol of Germanys default currency EUR = "€"
$locale = 'de_DE@currency=USD'; // get the currency symbol of USD in German locale = "$"

$formatter = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);

$currencySymbol = $formatter->getSymbol(\NumberFormatter::CURRENCY_SYMBOL);

Note, that the NumberFormatter is instantiated with the CURRENCY constant instead of DECIMAL here.

Since Yii 2.0.14 Yii has this method built-in in the Locale class.

]]>
0
[wiki] What SQL-Statement creates yii? Fri, 27 Jul 2018 11:28:13 +0000 https://www.yiiframework.com/wiki/2539/what-sql-statement-creates-yii https://www.yiiframework.com/wiki/2539/what-sql-statement-creates-yii Necip Necip

The usual way to find out what Yii has created for an SQL query is to mutilate the SQL in the sourcecode and call the program again so that the SQL statement with errors is displayed. Or you can use the SQL logger, which must be switched on and off each time and logs all SQL statements, which leads to an enormous slowdown in program execution and decelerates your workflow.

These all is not necessary if you use XDebug and place a breakpoint after the function "getCommandBuilder" in the CActiveRecord.php and take a closer look at the return value in $command.

This database access is created in yii:

yii-sql11.png?w=474

This code is called by the yii framework

yii-sql21.png?w=474

getCommandBuilder returns this data structure with the generated SQL statement:

yii-sql32.png?w=474

Path to CActiveRecord.php

C:\xampp\htdocs\your_project\yii\framework\db\ar\CActiveRecord.php

]]>
0
[wiki] How to organize Design "things" in Yii 2 (themes and layout) Thu, 23 Aug 2018 17:32:30 +0000 https://www.yiiframework.com/wiki/2538/how-to-organize-design-things-in-yii-2-themes-and-layout https://www.yiiframework.com/wiki/2538/how-to-organize-design-things-in-yii-2-themes-and-layout olissongs olissongs
  1. Via "theming"
  2. Using layouts
  3. Both
  4. UseCase one
  5. UseCase two

Sometimes the App needs a nicer look & feel, so its necessary to organize the assets for this and Yii can help a lot to make it easy. In this article I provide tips for handling multiple "Designs". I use these three features:

  • AssetBundle
  • Layouts
  • Themes

What do you need for desingning your website:

  • CSS files
  • JS files
  • some Images or other media.

Lets call it "DesignAssets"

What Yii needs:

  • one or more Layout files
  • the view files
  • AssetBundle set in the layout-file

Lets call it "DesignTemplates".

So how to bundle these and where is the best place to put them in your application directory?

Via "theming"

  • myYiiApp
    • ...
    • designs
      • myDesign1
        • put here all your "DesignTemplates" (AssetBundle,layout, and view folder/files, when using themes)

Using layouts

  • myYiiApp
    • ...
    • views
      • layouts
        • myDesign1.php (layout file)
      • ...

Both

  • myYiiApp

    • ...
    • web

      • designs
        • myDesign1
          • put here all your "DesignAssets" (css, js, img, etc.)
    • ...

So you can work with the default security file-rights for the correct purpose.

UseCase one

Write an App and distribute it to some Customer. Here can it be necessary that every customer wants a personal design.

Solution: Using themes

you config in your web.php or main.php (advanced template) whats documented here

if you need special "DesignAssets"

put your "DesignAssets" und the web directory myYiiApp/web/designs/myDesign1/css and js and img folders

customize your myYiiApp/designs/myDesign1/assets/MyDesignAsset.php

and your layout file myYiiApp/designs/myDesign1/layout/main.php

thats it.

UseCase two

you need several designs for e.g. controllers. so my remmmendation is using layouts, because easy switching in controller action.

Solution with layouts

there is no need to configure anything in the config files

if you need special "DesignAssets"

put your "DesignAssets" und the web directory myYiiApp/web/designs/myDesign1/css and js and img folders

create and customize your myYiiApp/assets/MyDesignAsset.php

and your layout file myYiiApp/views/layout/mydesign1.php

in your controller action set your layout.

public function actionIndex() {
    $this->layout = 'mydesign1';
}

may it helps your start with designing Yii.

]]>
0
[news] Yii 1.1.20 is released Fri, 06 Jul 2018 18:12:52 +0000 https://www.yiiframework.com/news/178/yii-1-1-20-is-released https://www.yiiframework.com/news/178/yii-1-1-20-is-released CeBe CeBe

We are very pleased to announce that Yii Framework version 1.1.20 is released. You can download it at yiiframework.com/download/.

This release is a release of Yii 1.1 that has reached maintenance mode and will, only receive necessary security fixes and fixes to adjust the code for compatibility with PHP 7 if they do not cause breaking changes. This allows you to keep your servers PHP version up to date in the environments where old Yii 1.1 applications are hosted and stay within the version ranges supported by the PHP team. Yii 1.1.20 is compatible with PHP 7.2 that, at the time of this writing, has an announced security support until November 30, 2020.

We recommend to use Yii 2.0 for new projects as well as introducing Yii 2.0 for developing new features in existing Yii 1.1 apps, as described in the Yii 2 guide. Upgrading a whole app to Yii 2.0 will, in most cases, result in a total rewrite so this option provides a way for upgrading step by step and allows you to keep old applications up to date even with low budget.

This release includes a few PHP 7 compatibility fixes and security improvements.

For the complete list of changes in this release, please see the change log. For upgrading, always make sure to read the upgrade instructions, however in this release there are no changes that require changes.

We would like to express our gratitude to all contributors who have spent their precious time helping improve Yii and made this release possible.

To comment on this news, you can do so in the related forum post.

]]>
0
[wiki] An alternative way to ElasticSearch Sun, 12 Aug 2018 07:49:50 +0000 https://www.yiiframework.com/wiki/2255/an-alternative-way-to-elasticsearch https://www.yiiframework.com/wiki/2255/an-alternative-way-to-elasticsearch Necip Necip

This article is for those who have dealt with the complexity of Elasticsearch or any other indexing machines and are looking for an easier way to index the existing database without additional effort.

Why this post?

The amount of data increases every day. As a result, the search in the databases becomes longer and longer. Conventional data structures must be realigned in order to be able to access information more quickly. There are already database systems like Elasticsearch that can do this. However, such systems also have disadvantages.

The most noticeable major drawbacks are:

  • Learning a new query language. SQL-Plugin won’t get you far or is not flexible enough.
  • The existing programs must be rewritten in order to process the new result sets appropriately.
  • The safety regulations must be defined again.
  • A second database must be set up, which in principle contains the same data.

Who will benefit from this post?

This information is useful for any programmer who wants to integrate an index database into his existing system in a simple way without additional effort.

The basic idea behind Indexing-machines

We will use this simple Table to demonstrate what an Index-machine does

Tablename: object

UID	TITLE	DESCRIPTION
4711	Rudyard Kipling	If you can keep your head when all about you …
4712	John Magee	I have slipped the surly bonds of Earth and danced the skies on laugher-silvered wings …
4713	Wiliam Wordsworth	Ten thousand saw I at a glance, Tossing their heads in sprightly dance…

With this request we can find very specific texts in this single table:

SELECT ID, Title, Description
FROM object
WHERE Description like '%head%'

But what if we want to find ‚%head%‘ in all tables of our database? We have to write a code to do this job for us. This is inefficent and will work very slowy. The idea behind Elasticsearch and other indexing tables is – so far I understood – to break the strings in single tokens. That means in a very easy way that we have to transform the horicontal order of the table into a vertical order.

Tablename: ncp_index

UID	TABLENAME	FIELDNAME	ID	TOKEN
1001	object	Description	4711	if
1002	object	Description	4711	you
1003	object	Description	4711	can
…				
1010	object	Description	4712	I
1011	object	Description	4712	have
1012	object	Description	4712	slipped
…				

We can tokenize any field of any table of our database into the table ncp_index. Now we can find with a single query very fast any (tokenized) word in our hole database.

SELECT Tablenname, Fieldname, Token
FROM ncp_index
WHERE Token like '%head%'

That is the secret of any Index-Searchengine. Yes, the ncp_index table has a lot of redundant data that we can normalize as follows:

Every field is stored in a system table and has a unique id. let us call it field_id Every content of a field has a lot of same words. These words should be stored only once in a separat words-table.

Our ncp_index table looks now so:

UID	FIELD_ID	ID	TOKEN_ID
1001	123	4711	1
1002	123	4711	2
1003	123	4711	31010	123	4712	4
1011	123	4712	5
1012	123	4712	6
…	
		
Systemtable: fields

UID	TABLENAME	NAME
122	object	Name
123	object	Description
…		

Tablename: word

UID	TOKEN
1	if
2	you
3	can
…	

Some basic examples

/**
 * @author ncp <necips@live.de>
 */
class NCPSearch
{
    /**
     * @param $model
     * @param $tablename
     * @param $fieldnames
     */
    public static function delete_ncp_search_item($model, $tablename) {
        $criteria = new CDbCriteria;
        $criteria->condition = "tablename = :tablename " .
                    "AND id = :id ";
        $criteria->params[":tablename"] = $tablename;
        $criteria->params[":id"] = $model->uid;
        NCPIndexModel::model()->deleteAll($criteria);
    }
    /**
     * @param $model
     * @param $tablename
     * @param $fieldnames
     */
    public static function update_ncp_search_item($model, $tablename, $fieldnames) {
        NCPSearch::delete_ncp_search_item($model, $tablename);
        NCPSearch::insert_ncp_search_item($model, $tablename, $fieldnames);
    }
    /**
     * @param $model
     * @param $tablename
     * @param $fieldnames
     */
    public static function insert_ncp_search_item($model, $tablename, $fieldnames) {
        foreach ($fieldnames as $fieldname) {
            $NCP_index_model = new NCPIndexModel("create");
            $NCP_index_model->tablename = $tablename;
            $NCP_index_model->fieldname = $fieldname;
            $NCP_index_model->id = $model->uid;
            $NCP_index_model->save();
            // a very simple way to tokenize the strings!
            $raw = strip_tags($model->{$fieldname});
            $tokens = explode( ' ', $raw);
            foreach ($tokens as $token) {
                $NCP_token_model = new NCPTokenModel("create");
                $NCP_token_model->NCP_index_uid = $NCP_index_model->uid;
                $NCP_token_model->token = $token;
                $NCP_token_model->save();
            }
        }
    }
    /**
     * @param $models
     * @param $tablename
     * @param $fieldnames
     */
    public static function insert_ncp_search_items($models, $tablename, $fieldnames) {
        foreach ($models as $model) {
            NCPSearch::insert_ncp_search_item($model, $tablename, $fieldnames);
        }
    }
}


// main.php:

// initialize ncp_search table once with all tables which has to be indexed in the main function
NCPSearch::insert_ncp_search_items(UserModel::model()->findAll(), "user", ["login", "mail", "name_last", "name_first"]);
NCPSearch::insert_ncp_search_items(DepartmentModel::model()->findAll(), "department", ["title", "description"]);
NCPSearch::insert_ncp_search_items(ObjectModel::model()->findAll(), "object", ["title", "description"]);
  

// model.php:

class Object : Model
{
  function afterSave()  {
    
    
     // insert this code to synchronize the informations on ncp_index
     if ($this->status === ObjectStatus::DELETED)
            NCPSearch::delete_ncp_search_item($this, "object");
        else
            NCPSearch::update_ncp_search_item($this, "object", ["title", "description"]);       
            
    ...
  }
  
  ...
  
}

Conclusion

These are my basic observations on this subject. These are the first steps to a search-engine that can index existing tables so that informations can be found quickly.

Thanks to

Github

https://github.com/Necip8/ncp_search

Homepage https://ncpup.wordpress.com

I hope this information helps you to build your own super search engine!

]]>
0
[news] Yii adopts SemVer since version 3.0.0 Tue, 25 Sep 2018 00:59:35 +0000 https://www.yiiframework.com/news/177/yii-adopts-semver-since-version-3-0-0 https://www.yiiframework.com/news/177/yii-adopts-semver-since-version-3-0-0 samdark samdark

Since version 3.0.0 Yii adopts SemVer versioning to achieve better predictability and compatibility with Composer.

Same will happen with extensions. They will adopt SemVer starting from next major versions.

SemVer is simple. Given a version number MAJOR.MINOR.PATCH, increment the:

  • MAJOR version when you make incompatible API changes,
  • MINOR version when you add functionality in a backwards-compatible manner, and
  • PATCH version when you make backwards-compatible bug fixes.

Yii 2.0.x versioning stays as is.

]]>
0
[news] Queue extension 2.1.0 released Wed, 23 May 2018 21:35:19 +0000 https://www.yiiframework.com/news/176/queue-extension-2-1-0-released https://www.yiiframework.com/news/176/queue-extension-2-1-0-released samdark samdark

We are very pleased to announce the release of Queue extension version 2.1.0.

Additionally to fixing bugs, the version brings two major enhancements on board. First, there is now Amazon SQS queue support.

Second, cli\Queue:EVENT_WORKER_LOOP worker loop event was added. It is called on each iteration between requests to queue.

Other than that, there are slightly updated documentation and new Japanese translation.

Full changelog is available at GitHub.

]]>
0
[wiki] Pjax GridView: refresh page after delete Tue, 24 Jul 2018 14:11:51 +0000 https://www.yiiframework.com/wiki/867/pjax-gridview-refresh-page-after-delete https://www.yiiframework.com/wiki/867/pjax-gridview-refresh-page-after-delete hehbhehb hehbhehb

Normally, after clicking the delete button in gridview, the record will be deleted and the page will refresh, but the page number in query string is lost. This is not always the case we expect.

How to refresh current page with pjax after deleting the record? It seems there is no very simple solution.

  1. Controller file

     public function actionDelete($id)
     {
         $this->findModel($id)->delete();
         if (Yii::$app->request->isAjax) {
             Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
             return ['success' => true];
         }
         return $this->redirect(['index']);
     }
    
  2. index.php (view file)

    <?php
     $this->registerJs("
         $(document).on('ready pjax:success', function() {
             $('.pjax-delete-link').on('click', function(e) {
                 e.preventDefault();
                 var deleteUrl = $(this).attr('delete-url');
                 var pjaxContainer = $(this).attr('pjax-container');
                 var result = confirm('Delete this item, are you sure?');                                
                 if(result) {
                     $.ajax({
                         url: deleteUrl,
                         type: 'post',
                         error: function(xhr, status, error) {
                             alert('There was an error with your request.' + xhr.responseText);
                         }
                     }).done(function(data) {
                         $.pjax.reload('#' + $.trim(pjaxContainer), {timeout: 3000});
                     });
                 }
             });
    
         });
     ");
    ?>
    
    <?php Pjax::begin(['id' => 'my_pjax']); ?>
     <div class="shop-index">
         <?= GridView::widget([
             'dataProvider' => $dataProvider,
             'filterModel' => $searchModel,
             'columns' => [
                 'id',
                 [
                     'class' => 'yii\grid\ActionColumn',
                     'buttons' => [
                         'update' => function ($url, $model) {
                             return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, [
                                 'class' => 'pjax-update-link',
                                 'title' => Yii::t('yii', 'Update'),
                             ]);
                         },
                         'delete' => function ($url, $model) {
                             return Html::a('<span class="glyphicon glyphicon-trash"></span>', false, [
                                 'class' => 'pjax-delete-link',
                                 'delete-url' => $url,
                                 'pjax-container' => 'my_pjax',
                                 'title' => Yii::t('yii', 'Delete')
                             ]);
                         }
                     ],
                 ],
             ],
         ]); ?>
     </div>
    <?php Pjax::end(); ?>
    
]]>
0
[news] Gii extension 2.0.7 released Wed, 02 May 2018 22:09:25 +0000 https://www.yiiframework.com/news/175/gii-extension-2-0-7-released https://www.yiiframework.com/news/175/gii-extension-2-0-7-released samdark samdark

We are very pleased to announce the release of Gii extension version 2.0.7. The release corrects Gii behavior adapting it to changes introduced in version 2.0.15 of the framework. Additionally there are fixes in model and CRUD generators.

]]>
0
[news] Swiftmailer extension 2.1.1 released Tue, 24 Apr 2018 23:26:51 +0000 https://www.yiiframework.com/news/174/swiftmailer-extension-2-1-1-released https://www.yiiframework.com/news/174/swiftmailer-extension-2-1-1-released samdark samdark

We are very pleased to announce the release of Swiftmailer extension version 2.1.1 that fixes yii\swiftmailer\Mailer::setTransport had no effect after sending of first message.

]]>
0
[news] Smarty extension 2.0.7 released Tue, 24 Apr 2018 23:11:22 +0000 https://www.yiiframework.com/news/173/smarty-extension-2-0-7-released https://www.yiiframework.com/news/173/smarty-extension-2-0-7-released samdark samdark

We are very pleased to announce the release of Smarty extension version 2.0.7 that fixes widget registration and rendering code generation inside subtemplates and adds an ability to use SmartyBC class.

]]>
0
[wiki] Configuring PhpStorm IDE for Yii 2 Fri, 27 Apr 2018 13:08:08 +0000 https://www.yiiframework.com/wiki/865/configuring-phpstorm-ide-for-yii-2 https://www.yiiframework.com/wiki/865/configuring-phpstorm-ide-for-yii-2 CeBe CeBe

There are a few settings and plugins that can enhance the development experience with Yii in PHPStorm or IntelliJ IDEA. This article explains how to get the most out of your IDE.

This arcticle is valid for Yii 2 and above, there is an older article for Yii 1.1.

Plugins

  • Yii2 Support adds many useful tools that improve working with Yii. It makes working with class configuration, DI and views easier.

  • Yii2 Inspections is a very useful plugin that adds Yii specific code inspections to PHPStorm. It helps for example to manage @property annotations for getters and setters as well as translation messages.

  • Php Inspections (EA Extended) is not directly Yii related but has a lot of additional code inspections that help you write better code. There is also a paid version that has even more features, especially security related inspections.

Project Setup

  • Exclude runtime directories from code search. Debug toolbar stores a lot of stuff that clutters search results.

    runtime - right click - Mark Directory As - Excluded

  • Enable composer integration to tell PHPStorm to separate vendor files from project files.

    composer.json - right click - Composer - Init Composer ...

PHPUnit and Codeception

PHPStorm has integrations for PHPUnit as well as Codeception, so you can run your tests directly from the IDE.

Settings for that can be found at Run - Edit Configurations....

To add your Codeception tests, click the + button, select Codeception. Then enter the following details:

  • Name: "Codeception tests" - or whatever you want to name it
  • Test Scope: Defined in the Configuration file
  • Use alternative configuration file: "codeception.yml"
  • In case PHPStorm asks you to do it, configure a PHP Interpreter in PHPStorm settings
  • Configure Codeception binary as vendor/bin/codecept

You can now run your tests directly from PHPStorm.

For PHPUnit the steps are similar but Yii application templates do not provide PHPUnit tests by default so the options depend on your setup.

]]>
0
[wiki] How to login from different tables in Yii2 Thu, 05 Apr 2018 13:57:25 +0000 https://www.yiiframework.com/wiki/864/how-to-login-from-different-tables-in-yii2 https://www.yiiframework.com/wiki/864/how-to-login-from-different-tables-in-yii2 androidelp androidelp

The Problem: Yii2 utilizes by default UserIdentity configured in config/web.php for connection, this object appy one table to authentication ('identityClass' => 'app\painel\models\User'). How to authentication from diferent tables? Solution: Create instances in web.php to uses UserIdentify. eg:

$user = \Yii::$app->user;  
$school = \Yii::$app->school; 
$teacher = \Yii::$app->teacher;

My config/web.php

'user' => [
	'class'=>'yii\web\User',
	'identityClass' => 'app\models\User',
	'enableAutoLogin' => false,
	'authTimeout' => 60*30,
	'loginUrl' => ['dashboard/login'],
	'identityCookie' => [
		'name' => '_panelUser',
	]
],
'school'=>[
	'class'=>'yii\web\User',
	'identityClass' => 'app\models\SchoolUser',
	'enableAutoLogin' => false,
	'authTimeout' => 60*30,
	'loginUrl' => ['dashboard-school/login'],
	'identityCookie' => [
		'name' => '_panelSchool',
	]	
],
'teacher'=> [
	'class'=>'yii\web\User',
	'identityClass' => 'app\models\TeacherUser',
	'enableAutoLogin' => false,
	'authTimeout' => 60*30,
	'loginUrl' => ['dashboard-teacher/login'],
    'identityCookie' => [
		'name' => '_painelTeacher',
	]
],

Note that for each there is a identifyClass and one view login. Now, we need to create the models:

namespace app\models;
use Yii;
// My user
class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface
{
    public static function tableName()
    {
        return '{{%user}}';
    }
    // to continues....

Model scholl:


namespace app\models;
use Yii;
// My School
class SchoolUser' extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface
{
    public static function tableName()
    {
        return '{{%schoolUser}}';
    }
    // to continues
    

Model Teacher:


namespace app\models;
use Yii;
// My School
class TeacherUser'' extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface
{
    public static function tableName()
    {
        return '{{%teacher}}';
    }
    // to continues....

Now In my example I want to have controllers for each type of access, without generating conflicts between them:

In Behavior of the controller i have defined for dashboard-school, teacher and user, the user object representing the authentication status or the ID of the user application component.


	//behaviors of the school
public function behaviors()
{
	return [
        'access' => [
            'class' => AccessControl::className(),
            'user'=>'school', // this user object defined in web.php
            'rules' => [
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
                [
                    'allow' => true,
                    'actions' => ['login'],                    
 'roles' => ['?'],

                ],
            ],
        ]
    ];
}

To use login:

//school
\Yii::$app->scholl->login($model, $this->rememberMe ? 3600*24*30 : 0);

//teacher
\Yii::$app->teacher->login($model, $this->rememberMe ? 3600*24*30 : 0);

For restrict access in views:

<?php if (!\Yii::$app->scholl->isGuest):?>
<h1>My scholl Name: <?=\Yii::$app->scholl->identity->name?>
<?php endif;?>

<?php if (!\Yii::$app->teacher->isGuest):?>
<h1>Teacher Name: <?=\Yii::$app->teacher->identity->name?>
<?php endif;?>

Always use the specific instance of the user you want to work with.

Criticism, suggestions and improvements, use the comments

]]>
0
[news] MongoDB extension 2.1.7 released Tue, 24 Apr 2018 23:09:22 +0000 https://www.yiiframework.com/news/172/mongodb-extension-2-1-7-released https://www.yiiframework.com/news/172/mongodb-extension-2-1-7-released samdark samdark

We are very pleased to announce the release of MongoDB extension version 2.1.7 that fixes Yii 2.0.14+ incompatibility and enhances Session component error reporting.

]]>
0
[news] Shell extension version 2.0.1 released Mon, 26 Mar 2018 14:53:24 +0000 https://www.yiiframework.com/news/171/shell-extension-version-2-0-1-released https://www.yiiframework.com/news/171/shell-extension-version-2-0-1-released samdark samdark

We are very pleased to announce the release of Shell extension version 2.0.1 which updates psy/psysh dependency to 0.8.x versions.

]]>
0
[wiki] Use non Gmail/Gsuite on Gcloud projects Sun, 15 Jul 2018 14:00:50 +0000 https://www.yiiframework.com/wiki/863/use-non-gmailgsuite-on-gcloud-projects https://www.yiiframework.com/wiki/863/use-non-gmailgsuite-on-gcloud-projects gogl92 gogl92

Small companies and startups use cheap email services or even Cpanel's mail services which are less secure and compete directly with bigger email providers like Microsoft with Outlook and Google with Gmail. This creates a problem when you try to use their services to send/receive emails from this cheap services. google-cloud-platform.png

Google says this: Google Compute Engine does not allow outbound connections on ports 25, 465, and 587. By default, these outbound SMTP ports are blocked because of the large amount of abuse these ports are susceptible to. In addition, having a trusted third-party provider such as SendGrid, Mailgun, or Mailjet relieves Compute Engine and you from maintaining IP reputation with your receivers.

Some time ago I had a project that requieres this, send emails using a cpanel mail services but we have Google Cloud services so when the client send me the credentials to put it in production the app crashes in a critical time, client will not pay to use Gsuite and I have all the stuff ready for production and configured in Google Cloud, so I found a solution.

  • Make sure you have swiftmail extension installed (it also comes with the basic and advance template)
  1. First get a Gmail or Gsuite account to use it as a bridge between emails. The name doesn't matter it will never be seen by final users. let's say mail_service54@gmail.com or use a Gsuite custom email. It is also important that you have full priviledges to this email as you will need it in the next step.
  2. Enable less secure apps to your email. [https://support.google.com/accounts/answer/6010255?hl=en](Official Docs here)
  3. Now configure the swiftmailer extension to send emails with your account. I use this config for gmail/gsuite accounts:
    'mailer' => [
             'class' => 'yii\swiftmailer\Mailer',
             'transport' => [
                 'class' => 'Swift_SmtpTransport',
                 'host' => 'smtp.gmail.com',
                 'username' => 'yourmail@gmail.com',
                 'password' => 'your password',
                 'port' => '587',
                 'encryption' => 'tls',
             ],
         ],
    
  4. Test that you can send an email so we can get sure the past configuration works well.
  5. After you can send an email, login into your account on the web and go to settings > Accounts and Import > Send mail as
  6. Do the import process of the other service/cpanel email, usually they will send you a link/code to the other email and you will have to confirm it.
  7. Now you can from your gmail account send mails as some other mail.
  8. Do this in your Yii code:
    Yii::$app->mailer->compose()
     ->setFrom('from@cpanel-mail.com')
     ->setTo('to@domain.com')
     ->setSubject('Message subject')
     ->setTextBody('Plain text content')
     ->setHtmlBody('<b>HTML content</b>')
     ->send();
    

    And that's it!

This is the first post of many about using Yii/Open Source in business and enterprise level becuase Open source != not cost.

]]>
0
[news] Finally releasing the new Yiiframework.com website Mon, 03 Sep 2018 15:54:45 +0000 https://www.yiiframework.com/news/169/finally-releasing-the-new-yiiframework-com-website https://www.yiiframework.com/news/169/finally-releasing-the-new-yiiframework-com-website CeBe CeBe

We are very happy to announce that the new yiiframework.com website is finally ready for deployment.

A huge thanks to Сергей Хильков (eshill) for his design work, to Jacob Moen and Nikola Trifunović for the countless hours spent on tweaking the frontend code and doing pages markup. Thanks to prodex, Robert Korulczyk and other contributors for fixes and additions.

There is a forum topic for discussion on this announcement.

Content

The new website will keep most of the content that is currently available online. We tried to keep existing content in the same places, so URLs should be the same as before. If you find that content is missing that was available before, please report to website project issues.

You can have a look at the new site on https://new.yiiframework.com/. Please note that this is just a preview. All content there will be re-imported destroying all the changes made when we'll deploy production version. Be careful with the forum however as it is real production one proxied to the new site :)

The new website puts more focus on the documentation, making Guide and API docs the first items in the navigation. You can now also directly search for API entries from the main navigation search field. You can search for class names and also method and property names, e.g. ActiveRecord.save() or just .save() or ::save().

Wiki and Extensions are available as before. Extensions now integrate with packagist, so if your extension is listed on packagist.org you no longer have to maintain two different places, the content is automatically synced with packagist if you enter the packagist URL in the extension properties.

The community section still has the old forum, which will continue to operate as before for now. We might replace the forum with a better solution in the future (Update Sep. 3, 2018: Moving the forum to Discourse). Also badges and ranking functionality has been ported from the old website.

Other information about Yii is now grouped under the "More" point in the navigation.

User accounts

We have imported all user accounts from the old website. You should be able to log in with your user name and password as before. If it does not work, there is a password reset option. In case you lost access to your account, we'll be there to help, please report to website project issues or write an email to admin@yiiframework.com.

You can now log in with github. To connect your existing login with your github account, log in regularly first, then go to your profile page (click on your user name on the top right) and authorize github. You won't need to type password again.

Feedback

If you have feedback about the new website, or you found a bug, please report in the Github issue tracker.

Roadmap

We are going to switch to the new website on March 23, 2018 in the time frame 8:00 to 12:00 UTC. During the switch, you will not be able to write comments, wikis, forum entries etc. Also the documentation may not be available. You can use http://stuff.cebe.cc/yii2docs/ to view the documentation.

We will be avilable in the Slack chat and on IRC #yii on freenode, so if you need help, get there.

]]>
0
[news] Releasing Yii 2.0.15 and database extensions with security fixes Mon, 09 Apr 2018 21:18:03 +0000 https://www.yiiframework.com/news/168/releasing-yii-2-0-15-and-database-extensions-with-security-fixes https://www.yiiframework.com/news/168/releasing-yii-2-0-15-and-database-extensions-with-security-fixes CeBe CeBe

Today we are releasing several versions for Yii 2.0.x and official extensions to fix a security issue.

The problem addressed in these patches exists in ActiveRecord shortcut methods findOne() and findAll(), which may allow SQL injection if input is not prepared properly. We consider this as a security issue in Yii because the documentation for these methods did not contain an explicit warning that there are cases when passing unfiltered user input might be dangerous. Thanks to analitic1983 for making us aware of the issue.

The nature of this issue does not solely exists in the Yii Framework but depends on how an application uses Yii. We have changed Yii to be more robust against the worst impact of the problem (SQL injection), but applications may still be vulnerable and changes to application code are necessary in some cases. As a safety measure, findOne() and findAll() are now limited to filter on columns that are AR properties only. In the following we will explain the problem in more detail and show which application code is affected and what needs to be adjusted on upgrade.

For discussion on this issue, there is a forum topic.

Summary of Affected Classes, Methods and Composer Packages

  1. Not Affected Code
  2. Affected Code
  • yii\db\ActiveRecord::findOne() and yii\db\ActiveRecord::findAll() in yiisoft/yii2 referenced as CVE-2018-7269. Methods allow SQL injection if input is not prepared properly. Attackers could probably execute arbitrary SQL queries or circumvent access checking methods applied on query level.
  • yii\redis\ActiveRecord::findOne() and yii\redis\ActiveRecord::findAll() in yiisoft/yii2-redis referenced as CVE-2018-8073. Methods allow remote code execution in redis servers lua script environment. Attackers could probably manipulate data on the redis server.
  • yii\elasticsearch\ActiveRecord::findOne() and yii\elasticsearch\ActiveRecord::findAll() in yiisoft/yii2-elasticsearch referenced as CVE-2018-8074. Methods may allow injecting different search condition than desired or cause an error response from the elasticsearch server.

Is my Application Affected?

  1. Not Affected Code
  2. Affected Code

This vulnerability affects all releases of the 2.0.x branch. It is fixed in Yii 2.0.15. For versions below 2.0.15, we have released two patch versions, 2.0.13.2 and 2.0.12.1, which apply the fix to 2.0.13.1 and 2.0.12 respectively. Users of 2.0.14, can upgrade to 2.0.15, there are no other changes made in this release.

Not Affected Code

The methods findOne() and findAll() accept a single argument, which can be scalar or array. If the calling code ensures that a scalar is passed or if client inputs cannot modify the array's structure, your application is not affected by this issue. The following code examples are not affected by this issue (examples shown for findOne() are valid also for findAll()):

// yii\web\Controller ensures that $id is scalar
public function actionView($id)
{
    $model = Post::findOne($id);
    // ...
}
// casting to (int) or (string) ensures no array can be injected (an exception will be thrown so this is not a good practise)
$model = Post::findOne((int) Yii::$app->request->get('id'));
// explicitly specifying the colum to search, passing a scalar or array here will always result in finding a single record
$model = Post::findOne(['id' => Yii::$app->request->get('id')]);

Affected Code

The following code however is vulnerable, an attacker could inject an array with an arbitrary condition and even exploit SQL injection:

$model = Post::findOne(Yii::$app->request->get('id'));

For the above example, the SQL injection part is fixed with the patches provided in this release, but an attacker may still be able to search records by different condition than a primary key search and violate your application business logic. So passing user input directly like this can cause problems and should be avoided.

How do I Upgrade?

  1. Not Affected Code
  2. Affected Code

If you are using Yii 2.0.14:

composer require "yiisoft/yii2":"~2.0.15.0"

If you are using Yii 2.0.13:

composer require "yiisoft/yii2":"~2.0.13.2"

If you are using Yii 2.0.12:

composer require "yiisoft/yii2":"~2.0.12.1"

If you are using yii2-redis extension:

composer require "yiisoft/yii2-redis":"~2.0.8"

If you are using yii2-elasticsearch extension:

composer require "yiisoft/yii2-elasticsearch":"~2.0.5"

Update: We have since released further patches to lower the impact of the BC break introduced by the security fix, so you get versions 2.0.15.1, 2.0.13.3 and 2.0.12.2 from the above.

Upgrading isn't Enough!

  1. Not Affected Code
  2. Affected Code

Upgrading Yii addresses the SQL injection but doesn't make findOne() and findAll() safe in general. Check all usages of findOne() and findAll() in your application. Also note, that where() and filterWhere() never escape column names, so if you need to pass a variable as a column name, make sure it is safe.

]]>
0
[wiki] Yii2 RESTful API with OAuth 2.0 Sun, 25 Mar 2018 02:00:49 +0000 https://www.yiiframework.com/wiki/862/yii2-restful-api-with-oauth-2-0 https://www.yiiframework.com/wiki/862/yii2-restful-api-with-oauth-2-0 sirin_ibin sirin_ibin

https://cdn.pbrd.co/images/GMN5ROs.jpg

Overview

This article is for the one’s who is already working with PHP/Yii2 or who wants to quick start developing a RESTful API using Yii2 framework with

  1. OAuth 2.0 authentication
  2. A developer dashboard
  3. API documentation template

Here I’m sharing the Live demo and Source code of a RESTful API with OAuth2 authentication/security developed using Yii2 framework You can use this if you want to quick start developing your own custom RESTful API by skipping 95% of your scratch works. Hopefully this will save lot of your time as this API includes all the basic stuffs you need to get started.

Developer Dashboard

This API also includes a developer dashboard with the API documentation which is developed in Yii2 framework. This will be useful to manage your developers access to the API documentation.

Why Yii2?

Yii2

It's Fast, It’s Secure and Professional!. Yii comes with rich features: MVC, DAO/ActiveRecord, I18N/L10N, caching, authentication and role-based access control, scaffolding, testing, etc. It can reduce your development time significantly.

What is a RESTful API?

REST is an architectural style for building APIs. It stands for “Representational State Transfer”. It means when we build an API, we build it in a way that HTTP methods and URIs mean something, and the API has to respond in a way that’s expected.

Something about OAuth 2.0

The OAuth 2.0 is an authorization framework which enables a third-party application to obtain limited access to an HTTP service.

DEMO

http://yii2-rest.dockerboxes.us

Login: developer/developer

Source Code

https://github.com/sirinibin/Yii2-RESTful-API-with-OAuth2

Official Documentation

Documentation for this RESTful API can be found on the Yii 2.0 RESTful API with OAuth 2.0 Documentation. Security Vulnerabilities

If you discover a security vulnerability within this API, please send an e-mail to Sirin k at sirin@nintriva.com. All security vulnerabilities will be promptly addressed.

Installation instructions

https://github.com/sirinibin/Yii2-RESTful-API-with-OAuth2

Sirin K

]]>
0
[wiki] How to get SEO friendly URL using Model and new getUrl() function Thu, 21 Sep 2017 04:25:33 +0000 https://www.yiiframework.com/wiki/861/how-to-get-seo-friendly-url-using-model-and-new-geturl-function https://www.yiiframework.com/wiki/861/how-to-get-seo-friendly-url-using-model-and-new-geturl-function shivam4u shivam4u

We all need SEO friendly URLs for our projects. its not always good to call route with params so we can generalise it for all models using a common function.

Following the general convention of model and control sharing common name, we can use this code to get seo friendly URL.

public function getControllerID() {
		$modelClass = get_class ( $this );
		$pos = strrpos ( $modelClass, '\\' );
		$class = substr ( $modelClass, $pos + 1 );
		return Inflector::camel2id ( $class );
	}
	public function getUrl($action = 'view', $id = null) {
		$params = [ 
				$this->getControllerID () . '/' . $action 
		];
		if ($id != null)
			$params ['id'] = $id;
		else
			$params ['id'] = $this->id;
		// add the title parameter to the URL
		$params ['title'] = ( string ) $this;
		// absolute url
		return Yii::$app->getUrlManager ()->createAbsoluteUrl ( $params, true );
	}

In code code where ever you need to url to a model , you just call $model->url or $model->getUrl('view').

You may have to additionally update urlManager in config with rules for pretty url.

'<controller:[A-Za-z-]+>/<id:\d+>/<title>' => '<controller>/view',
								'<controller:[A-Za-z-]+>/<id:\d+>' => '<controller>/view',
								'<controller:post>/<id:\d+>/<title>' => 'blog/view',
								'<controller:[A-Za-z-]+>/<action:[A-Za-z-]+>/<id:\d+>/<title>' => '<controller>/<action>',
								'<controller:[A-Za-z-]+>/<action:[A-Za-z-]+>/<id:\d+>' => '<controller>/<action>',
	

you will get url like this.

http://localhost/link/650/need-a-professional-developer

]]>
0
[wiki] Yii2 Report Grid Mon, 26 Mar 2018 10:10:29 +0000 https://www.yiiframework.com/wiki/860/yii2-report-grid https://www.yiiframework.com/wiki/860/yii2-report-grid chrisb34 chrisb34

A Yii2 Gridview designed specifically for reporting

  1. Why is this significant
  2. Widget Setup
  3. Column Configuration

There are some very advanced grids in the Yii2 community, specifically Kartik's amazing gridview extensions but they all designed for interactive screen use.

ReportGrid is designed to provide report results to users, without filtering or sorting.

But more importantantly it has sub-totalling and report totalling built into the gridview itself.

Why is this significant

Because it enables you to use closures (anonymous functions) within the sub-total fields. For example, say we want to build a report on order items, with a break at order level. At the order level, we want to report something off the order model but the dataProvider is on the order-item level.

With ReportGrid, we can do this by using a closure on the sub-total to return the $model->order->some_relationship->some_value

Installation The preferred way to install this extension is through composer. Either run:

$ php composer.phar require chrisb34/reportgrid "@dev"

or add:

"chrisb34/yii2-report-grid": "@dev"

to the require section of your composer.json file. Then run:

php composer.phar update

to get the updated package on your application install.

Widget Setup

As with most Yii2 widgets, you control the using options on widget creation. This widget is based on the Yii2 gridview widget, so anything mentioned here is over and above the base options on the gridview widget

Note: that this widget does not support pagination. It actively switches pagination off in the dataProvider

  • controlBreak : boolean, turn on all this functionality. defaults to true. If set to false will make this widget behave like a notmal gridView

  • totalRowOptions : array, array list of options eg: [ 'class'=>'total-row']

  • totalsHeader : boolean, whether to repeat the table header row just before the report totals.

  • exportCSV : boolean, whether to include the 'Export to CSV' button

  • afterRow : closure, provides the ability to output an extra row after every model row. Closure call in the format function( $model, $key, $index)

  • pageSummary : closure, provides the ability to output an extra row at the end of the report. Closure call in the format function( $model, $key, $index)

Usage

echo ReportGrid::widget([
    'dataProvider' => $dataProvider,
    'columns' => $gridColumns,
    'controlBreak' => true,
    'totalRowOptions' => ['class'=>'total-row'],
    'totalsHeader' => true,
    'exportCSV' => true,
    'afterRow' => function( $model, $key, $index)  {
    	return $someContent;
    },
    'pageSummary' => [
            Html::tag('tr','<td colspan=10><h1>Report Summary goes here</h1></td>'),
    ]
    
    ]);

Column Configuration

When you use sub-totalling in a report, your report layout must follow the same structure as your query. So the first thing is to define your query with the results in the correct order.

When defining columns, you first need to specify which columns will cause your report to break. Normally, these will also be in the same order as the columns themselves but this is not mandatory.

  • subTotalOn : integer, The break level runs from 1 upwards and the gridview then uses level zero as the report totals.

  • subTotal : array | boolean, with the following options;
    • if set to true, then reportGrid uses the attribute value, summing the model->attribute or model->value amounts.
    • value : string|attribute name|closure ~ function($model, $key, $index, $widget, $break) {}, the value used by the totalling function as opposed to the value displayed.
    • breakValue : string|attribute name|closure ~ function($model, $key, $index, $widget, $break) {}, what to display in the sub-total cell. note the addition of the $break variable which can be used to determine the current break level. For example: you may use if ($break!=1) return $model->some_amount; else return ' ';
    • showOnBreak | hideOnBreak : integer, show/hide the sub-total at the specified break level
    • format : boolean, uses the yii2 formatter to pre-format the cell contents eg: currency, html, text
    • totalMethod : the only available option at this stage is ReportColumn::TOTAL_BREAKDOWN, This will provide a summary table at the control break of this column values and summed values specified by totalOn.
    • totalOn : string|attribute name|closure ~ function($model, $key, $index, $widget, $break) { return $model->attribute; },, the value to be applied to the totalling.

Usage

'subTotal' => [
       'breakValue' => function($model, $key, $index, $widget, $break) {
           if ($break == 1)
               return   $model->category_name; 
           elseif ($break == 0)
               return 'REPORT TOTAL';
       },
       'hideOnBreak' => 2
       ]
	

for more info see: yii2.percipero.com

]]>
0
[wiki] How to make UrlManager createAbsoluteUrl work with sub-domains Sun, 25 Mar 2018 02:06:47 +0000 https://www.yiiframework.com/wiki/858/how-to-make-urlmanager-createabsoluteurl-work-with-sub-domains https://www.yiiframework.com/wiki/858/how-to-make-urlmanager-createabsoluteurl-work-with-sub-domains wadeshuler wadeshuler

Upon creating my Yii2 Members System, I have ran into a few snags along the way that forced me to extend and bend Yii2 to my will.

I will describe how my app is intended to work, so you know how this article fits into your project needs. My members system is designed to resemble the good ole' days, when we had site.com/members and site.com/admin. It is common to also have them on sub-domains as members.site.com and admin.site.com . The sub-domains add an extra layer of security, especially with the admin on it's own sub-domain separate from the users. Now, that alone wont save you from everything, but as I said, it's just an extra layer. Some of us need them separated like this, because the sub-domains are on different servers. For example, your API could be on an independent server. Or maybe your users and admin sections are on different servers or IPs. If you look at large systems like Microsoft or Adobe, they have many servers for many different uses. Users, API, time, activation, fonts, and many more... So it isn't crazy to want your apps on different sub-domains.

Unfortunately, Yii2 is flat out retarded when it comes to sub-domains. Hopefully they will implement what I am about to show you, or a better version of this. I am always open to a better way to do this.

When I Googled this issue, there wasn't much out there. I found info related to how to link to backend from frontend, and that is even in the official Yii2 docs. That DOES NOT work with sub-domains though! It only works for directories, ie: what comes after your domain, not the sub-domain. I did find one GitHub repo from Postor. Problem was, it wasn't very intuitive and looks like a broken unfinished repo. So I feel the one I made was better.

So in this guide, I am going to show you the best and only way I found to create links to another one of your Yii apps (ie: backend or frontend) that are on a sub-domain.

My method for handling sub-domains

Unfortunately, there isn't an accurate and reliable way to grab only the domain name. A bunch of regex or stripping, or pulling from a huge list of valid domain extensions, etc. Nothing you want running on a site with tons of users, it will create a bottle neck real quick. Yeah, you could implement caching and you should for large volume sites. However, I prefer to cache lean efficient code instead of using caching to save my rear on terrible logic.

So this REQUIRES us to define our domain and sub-domains in our common bootstrap file.

common/config/bootstrap.php

// URL Manager Aliases
Yii::setAlias('@domainName', (YII_ENV === 'dev') ? 'yii2-members-system.dev' : 'yourlivesite.com');
Yii::setAlias('@frontendSubdomain', 'users');
Yii::setAlias('@backendSubdomain', 'admin');

Create common/components/UrlManager.php

<?php
namespace common\components;

use Yii;
use yii\helpers\Url;
use yii\base\InvalidConfigException;

class UrlManager extends yii\web\UrlManager
{
    public $subDomain;
    public $domainName;

    protected $_hostInfo;

    public function getProperDomain()
    {
        if ( ! isset($this->domainName) || empty($this->domainName) ) {
            throw new InvalidConfigException('Request requires a domain name to be configured!');
        }

        $subDomain = (isset($this->subDomain) && !empty($this->subDomain)) ? $this->subDomain : '';
        $domain = empty($subDomain) ? '' : $subDomain . '.';
        $domain .= $this->domainName;

        return $domain;
    }

    public function getHostInfo()
    {
        if ($this->_hostInfo === null)
        {
            $secure = Yii::$app->getRequest()->getIsSecureConnection();
            $http = $secure ? 'https' : 'http';

            if (isset($_SERVER['HTTP_HOST'])) {
                $this->_hostInfo = $http . '://' . $this->getProperDomain();
            } elseif (isset($_SERVER['SERVER_NAME'])) {
                $this->_hostInfo = $http . '://' . $this->getProperDomain();
                $port = $secure ? $this->getSecurePort() : $this->getPort();

                if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) {
                    $this->_hostInfo .= ':' . $port;
                }
            }
        }
        return $this->_hostInfo;
    }

}

Now in whichever app your needing to link to another subdomain, you need to edit it's main config. So if in backend you need to link to frontend (or mainsite needs to link to frontend as in my members system), then edit your backend config.

Add this to your config under the components array:

'urlManagerFrontend' => [
    'class' => 'common\components\UrlManager',
    'subDomain' => Yii::getAlias('@frontendSubdomain'),
    'domainName' => Yii::getAlias('@domainName'),
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'rules' => [
    ],
],

Now, wherever you need to create a link (or get the url for any reason) use CreateAbsoluteUrl inside the new UrlManager like so:

Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/login'])

In my app, it generates a link for my mainsite to the users app: http://users.yii2-members-system.dev/site/login. This was so on my mainsite I can link to the user's subdomain for them to login.

I hope this helps someone, and I hope Yii actually adopts a solution for this sort of linking and handling sub-domains.

]]>
0
[wiki] Show raw SQL query Sat, 14 Jan 2017 19:53:41 +0000 https://www.yiiframework.com/wiki/857/show-raw-sql-query https://www.yiiframework.com/wiki/857/show-raw-sql-query darioo darioo

Here's a quick tip to dump the SQL for query.

$query = new Books::find()->where('author=2');
echo $query->createCommand()->sql;

or to get the SQL with all parameters included try:

$query->createCommand()->getRawSql()

Thanks to http://chris-backhouse.com/Yii2-Output-the-SQL-from-a-query-builder/1027

]]>
0
[wiki] Working with relational removals by yii2 Mon, 05 Jun 2017 03:57:13 +0000 https://www.yiiframework.com/wiki/856/working-with-relational-removals-by-yii2 https://www.yiiframework.com/wiki/856/working-with-relational-removals-by-yii2 androidelp androidelp

This tutorial shows you how to safely remove records between relationships.

First we create three tables using a Many to Many relationship.

Imagem da relacao

Important: Apply cascade to foreign key constraints for update and delete.

The cascade feature will allow you to remove the foreign keys along with the line you want to delete and helps keep your code to a minimum.

Script SQL the ralation has.

CREATE TABLE `tests_has_games` (
   `tests_id` int(11) NOT NULL,
   `games_id` int(11) NOT NULL,
   PRIMARY KEY (`tests_id`,`games_id`),
   KEY `fk_tests_has_games_games1_idx` (`games_id`),
   KEY `fk_tests_has_games_tests_idx` (`tests_id`),
   CONSTRAINT `fk_tests_has_games_games1` FOREIGN KEY (`games_id`) REFERENCES `games` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
   CONSTRAINT `fk_tests_has_games_tests` FOREIGN KEY (`tests_id`) REFERENCES `tests` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin

Step 2: Create models: (to use generator gii, this system create model with relations of the table). ModelGames:

public function getTestsHasGames()
    {
        return $this->hasMany(TestsHasGames::className(), ['games_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTests()
    {
        return $this->hasMany(Tests::className(), ['id' => 'tests_id'])->viaTable('{{%tests_has_games}}', ['games_id' => 'id']);
    }

Model Tests:

public function getTestsHasGames()
    {
        return $this->hasMany(TestsHasGames::className(), ['tests_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getGames()
    {
        return $this->hasMany(Games::className(), ['id' => 'games_id'])->viaTable('{{%tests_has_games}}', ['tests_id' => 'id']);
    }

Step 3: Simple Removal Functions in controllers:

public function actionDeletarTest($id)
  {

    $session = \Yii::$app->session;

    $testes = Tests::findOne($id);

    if($testes->delete())
    {
      $session->addFlash('resposta', [
        'type'=>'success',
        'msg'=>'Teste deletado com sucesso.'
      ]);
    }else{
      $session->addFlash('resposta', [
        'type'=>'danger',
        'msg'=>'Erro encontrado favor resolver.'
      ]);
    }

    return $this->redirect(['site/delete-relations']);

  }

Other Methods

public function actionDeleteListGames()
  {
    $array_id = [1,2,3,4];

    $games = Games::find()->where(['in','id',$array_id])->all();

    foreach($games as $k => $game)
    {
      $game->delete();
    }

  }
     // deletando de vinculo
     public function actionDeleteTestAll()
     {
       $game = Games::findOne(1);
       foreach($game->tests as $test)
       {
          $test->delete();
       }
     }


public function actionDeleteTheRelation($id)
  {


    $game = Games::find()->joinWith(['tests'=>function($q){
      return $q->where(['like','nome','proccess'])
    }])->where(['id'=>$id])->one();

    foreach($games->tests as $k => $test)
    {
      $test->delete();
    }

  }

Get All code in Your text to link here...

]]>
0
[wiki] Interactive mode command-line command for Yii1 Mon, 21 Nov 2016 12:41:10 +0000 https://www.yiiframework.com/wiki/854/interactive-mode-command-line-command-for-yii1 https://www.yiiframework.com/wiki/854/interactive-mode-command-line-command-for-yii1 trejder trejder

For one of my projects I needed an interactive console command in Yii 1, i.e. the one that is gathering all information from user in an interactive mode (a serie of questions and answers displayed directly in the console), ignoring command-line arguments at all.

This is an example (or rather a bare foundation, as this actually is doing nothing) of such solution. It has some console text formatting methods (borders, text alignment) plus simple method for gathering user response.

The code

Here is an implementation for Yii 1 of mentioned solution.

class ImportCommand extends CConsoleCommand
{
    const BORDER_WIDTH = 80;

    public function actionIndex($args)
    {
        $message = $this->alignText('This text is aligned to the right border...', 'right')."\n";
        $message .= "\n";
        $message .= $this->alignText('...this one is centered...', 'center')."\n";
        $message .= "\n";
        $message .= $this->alignText('...and this is left as is, so aligned to the left border!', 'left')."\n";
        $message .= "\n\n";
        $message .= $this->alignText('Finally we have a really long text, no matter, how aligned, that is going to be cut right there, where it should');

        $this->drawBorder($message);

        $this->readStdin();

        echo 'You selected: '.$this->readStdin('Enter any alphabet letter, please...');
        
        $this->clearStdin();
    }

    /**
     * Aligns text to given margin.
     * 
     * @param  string $text       Text to be aligned.
     * @param  string $align      Align method: 'right', 'center' or 'left' (default == empty string).
     * @param  integer $lineWidth Maximim line width. If not specified, class' constant will be used instead.
     * 
     * @return string             Aligned text, pad with trailing and following spaces.
     */
    public function alignText($text, $align = 'left', $lineWidth = null)
    {
        $lineWidth = is_null($lineWidth) ? self::BORDER_WIDTH : $lineWidth;
        $lineWidth = $lineWidth - 4;

        $text = strlen($text) > $lineWidth ? substr($text, 0, $lineWidth) : $text;

        if($align === 'right')
        {
            return str_repeat(' ', $lineWidth - strlen($text)).$text;
        }

        if($align === 'center')
        {
            $margin = floor($lineWidth  / 2) - floor(strlen($text) / 2);

            return str_repeat(' ', $margin).str_pad($text, $margin , ' ');
        }
        else return $text;
    }

    /**
     * Draws console-like (DOS-like?) text border around passed text.
     * 
     * @param  string $text       Text to be outlined in a fancy-like text border.
     * @param  integer $lineWidth Maximim width of each border line. See above for details.
     */
    public function drawBorder($text, $lineWidth = null)
    {
        $lineWidth = is_null($lineWidth) ? self::BORDER_WIDTH : $lineWidth;
        $lineWidth = $lineWidth > 80 ? 80 : $lineWidth;

        $nl = $lineWidth === 80 ? '' : "\n";

        echo str_repeat('*', $lineWidth).$nl;

        echo '*'.str_repeat(' ', $lineWidth - 2).'*'.$nl;

        foreach(explode("\n", $text) as $line) echo '* '.str_pad($line, $lineWidth - 4, ' ').' *'.$nl;

        echo '*'.str_repeat(' ', $lineWidth - 2).'*'.$nl;

        echo str_repeat('*', $lineWidth).$nl;
    }

    /**
     * Get user entry / decision.
     * 
     * @param  string $message Information to be displayed, when requiring user to enter something.
     * 
     * @return string          User entry.
     */
    public function readStdin($message = 'Continue [Y/N]?')
    {
        echo $message;

        $handle = fopen("php://stdin","r");
        $line = fgets($handle);

        return trim($line);
    }
    
    /**
     * Clears console window.
     *
     * The implementation used here can't be anymore ugly, but it is the only one,
     * that is working, when using GitBash. All other methods fails:
     *
     * http://stackoverflow.com/a/24327758/1469208
     * http://stackoverflow.com/a/29193143/1469208
     */
    public function clearStdin()
    {
        for ($i = 0; $i < 50; $i++) echo "rn";
    }
}

Execution

To get this thing working, put all the above code in a separate .php file and save it to protected/commands path under ImportCommand.php name.

Then open console window, navigate to protected folder in your application and execute:

yiic import

Of course, rename both file and class name, if you want to use this command under different name.

Also make sure that you have set correctly everything around running console commands.

]]>
0
[wiki] REST API and null values in XML Fri, 11 Nov 2016 00:26:44 +0000 https://www.yiiframework.com/wiki/853/rest-api-and-null-values-in-xml https://www.yiiframework.com/wiki/853/rest-api-and-null-values-in-xml marko60 marko60

I have been working on a REST API using the excellent tools provided by Yii2. My problem was that I have to differentiate between empty values and null values. In other words, <elem></elem> is different from null as it represents an empty string. Also, although some use <elem/> to represent a null value it should still be interpreted as an empty string. In other cases, the absence of the element is taken to represent a null value, but this may create problem with some parsers.

After some research, it appears that the correct way of describing a null value is <elem xsi:nil="true"/>.

However this is not supported by the current implementation of XmlResponseFormatter because values are always appended as DOMText. This means that, even is I pass a PHP null value, I get <elem></elem>.

Therefore, I have extended XmlResponse Formatter as follows.

Firstly, the function format() must be modified because creating $root as DOMElement makes it immutable while I need to attach the xsi: namespace definition. Therefore I use:

...
$dom = new DOMDocument($this->version, $charset);
// A writeable element is created and the namespace added
$root = $dom->createElement($this->rootTag);
$root->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$dom->appendChild($root);
...

Then I have modified the buildXml function as follows:

protected function buildXml($element, $data){
  if (is_array($data) ||
    ($data instanceof \Traversable && $this->useTraversableAsArray && !$data instanceof Arrayable)
  ) {
    foreach ($data as $name => $value) {
      if (is_int($name) && is_object($value)) {
        $this->buildXml($element, $value);
      } elseif (is_array($value) || is_object($value)) {
        $child = new DOMElement(is_int($name) ? $this->itemTag : $name);
        $element->appendChild($child);
        $this->buildXml($child, $value);
      } else {
        $child = new DOMElement(is_int($name) ? $this->itemTag : $name);
        $element->appendChild($child);
        // Checks if the value is null and creates a null MXL element
        if ($value === null) {
          $child->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance','xsi:nil','true');
        } else {
          $child->appendChild(new DOMText((string) $value));
        }
      }
    }
  } elseif (is_object($data)) {
    $child = new DOMElement(StringHelper::basename(get_class($data)));
    $element->appendChild($child);
    if ($data instanceof Arrayable) {
      $this->buildXml($child, $data->toArray());
    } else {
      $array = [];
      foreach ($data as $name => $value) {
        $array[$name] = $value;
      }
      $this->buildXml($child, $array);
    }
  } else {
    // Checks if $data is null and adds xsi:nil to $element
    if ($data === null) {
      $element->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance','xsi:nil','true');
    } else {
      $element->appendChild(new DOMText((string) $data));
    }
  }
}

This way, if the value of the XML element is null, I get <element xsi:nil="true"/> which is more correct while, if the value is an empty string, I get <element></element> as expected.

I hope this would be useful to somebody and maybe the Yii2 could consider this improvement in a future release.

]]>
0
[wiki] Optimize Scenarios for yii2 Thu, 12 Apr 2018 13:24:16 +0000 https://www.yiiframework.com/wiki/852/optimize-scenarios-for-yii2 https://www.yiiframework.com/wiki/852/optimize-scenarios-for-yii2 androidelp androidelp

Working with scenarios, with models that can receive many modifications in their rules or structures as development evolves, can create disruptions in the rescue process.

One way to avoid this disorder is to encapsulate the information defined for the scenarios and to have a single point of customization.

For this we need to create constants for each scenario, note: once you define a scenario, you will need to use scenarios for any database edition that uses this model.

In model

class MyModel extends \yii\db\ActiveRecord
{

  const SCENARIOCRIATE = 'scenariocriate';
  const SCENARIOUPDATE = 'scenarioupdate';

    // scenarios encapsulated
    public function getCustomScenarios()
    {
      
      return [
          self::SCENARIOCRIATE      =>  ['user_id', 'name', 'desc', 'published','date_create'],
          self::SCENARIOUPDATE      =>  ['user_id', 'name', 'desc', 'date_update'],
      ];
    }
    // get scenarios
    public function scenarios()
    {
        $scenarios = $this->getCustomScenarios();
        return $scenarios;
    }

    // modify itens required for rules
    public function ModifyRequired()
    {

      $allscenarios = $this->getCustomScenarios();
      // published not required
      $allscenarios[self::SCENARIOCRIATE] = array_diff($allscenarios[self::SCENARIOCRIATE], ['published']);
      return $allscenarios;

    }

    public function rules()
    {
      // get scenarios
      $allscenarios = $this->ModifyRequired();
        return [
            [$allscenarios[self::SCENARIOCRIATE], 'required', 'on' => self::SCENARIOCRIATE],
            [$allscenarios[self::SCENARIOUPDATE], 'required', 'on' => self::SCENARIOUPDATE],
            [['user_id'], 'integer'],
            [['name','desc'], 'string', 'max' => 70],
            [['date_create', 'date_update'], 'date', 'format' => 'php:Y-m-d H:i:s'],
        ];
    }

GetCustomScenarios will be used for when you need to make column modifications.

The ModifyRequired is used to remove from the required, because at this point will be used getCustomScenarios for the save.

In Controller

public function actionIndex()
{

    $model = new MyModel;
    $model->scenario = 'scenariocriate';

    if ($model->load(\Yii::$app->request->post())){

        // force my columns
        if($model->save()){
          //return true
        } 
    }
}

It may seem redundant, but constructing the controller in this way, avoids having problems with maintenance of database tables, the adjustments will be made only in the model, since there is no reference of communes in the controller.

]]>
0
[wiki] Yii2 GridView Sorting and Searching with a Junction Table Column(Many to Many Relationship) Tue, 08 Nov 2016 02:34:38 +0000 https://www.yiiframework.com/wiki/851/yii2-gridview-sorting-and-searching-with-a-junction-table-columnmany-to-many-relationship https://www.yiiframework.com/wiki/851/yii2-gridview-sorting-and-searching-with-a-junction-table-columnmany-to-many-relationship Amjad Khan Amjad Khan
  1. tblgroups
  2. tblcontacts
  3. tblcontactsgroups(junction table)

Following is the table structure

tblgroups

CREATE TABLE IF NOT EXISTS `tblgroups` (
  `id` int(11) NOT NULL,
  `groupname` varchar(150) NOT NULL,
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1=Acitve,2=Inactive',
  `date` datetime NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

tblcontacts

CREATE TABLE IF NOT EXISTS `tblcontacts` (
  `id` int(11) NOT NULL,
  `firstname` varchar(100) NOT NULL,
  `lastname` varchar(100) NOT NULL,
  `company` varchar(100) NOT NULL,
  `address` text NOT NULL,
  `phone` varchar(50) NOT NULL,
  `mobile` varchar(50) NOT NULL,
  `fax` varchar(50) NOT NULL,
  `pemail` varchar(100) NOT NULL,
  `semail` varchar(100) NOT NULL,
  `country` varchar(55) NOT NULL,
  `websiteurl` varchar(100) NOT NULL,
  `gender` tinyint(4) NOT NULL COMMENT '1=male,2=female,3=shemale',
  `birthday` varchar(10) NOT NULL,
  `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1=Active,2=Inactive',
  `sentstatus` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1=sent,2=not sent',
  `addeddate` datetime NOT NULL,
  `updateddate` datetime NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;

tblcontactsgroups(junction table)

CREATE TABLE IF NOT EXISTS `tblcontactsgroups` (
  `id` int(11) NOT NULL,
  `contact_id` int(11) NOT NULL,
  `group_id` int(11) NOT NULL,
  `dateadded` datetime NOT NULL
) ENGINE=MyISAM AUTO_INCREMENT=20085 DEFAULT CHARSET=latin1;

First of all with the help of gii crud generators we will create the crud for all these tables including models and controllers,tblcontactsgroups is the table having many to many relation between tblcontacts and tblgroups. In the Contacts Model generated from tblcontacts we will use the hasMany relationship as follows

public function getGroups() {
        return $this->hasMany(Groups::className(), ['id' => 'group_id'])->viaTable('tblcontactsgroups', ['contact_id' => 'id']);
    }

In Groups model we will insert the following code

public function getContacts() {
        return $this->hasMany(Contacts::className(), ['id' => 'contact_id'])->viaTable('tblcontactsgroups', ['group_id' => 'id']);
    }

The most important model is the ContactsSearch Model we will make the following changes in it first of all we declare the groupname(related groups table attribute) public property in ContactsSearch Model

class ContactsSearch extends Contacts {

    /**
     * @inheritdoc
     */
    // public group_id;
    public $groupname;
............................

we will also include groupname in the rules

public function rules() {
        return [
            [['id', 'gender', 'status', 'sentstatus'], 'integer'],
            [['firstname', 'lastname', 'company', 'address','groupname', 'phone', 'mobile', 'fax', 'pemail', 'semail', 'country', 'websiteurl', 'birthday', 'addeddate', 'updateddate'], 'safe'],
        ];
    }

and then we will manipulate the search method in ContactsSearch Model like this

public function search($params) {
        $query = Contacts::find()->innerJoinWith('groups', true);
        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'sort' => ['attributes' => ['firstname', 'lastname', 'groupname', 'email', 'pemail']]
        ]);

        $this->load($params);
        if (!$this->validate()) {
            // uncomment the following line if you do not want to return any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }

        // grid filtering conditions
        $query->andFilterWhere([
            'id' => $this->id,
            'gender' => $this->gender,
            'status' => $this->status,
            'sentstatus' => $this->sentstatus,
            'addeddate' => $this->addeddate,
            'updateddate' => $this->updateddate,
        ]);

        $query->andFilterWhere(['like', 'firstname', $this->firstname])
                ->andFilterWhere(['like', 'lastname', $this->lastname])
                ->andFilterWhere(['like', 'company', $this->company])
                ->andFilterWhere(['like', 'address', $this->address])
                ->andFilterWhere(['like', 'phone', $this->phone])
                ->andFilterWhere(['like', 'mobile', $this->mobile])
                ->andFilterWhere(['like', 'fax', $this->fax])
                ->andFilterWhere(['like', 'pemail', $this->pemail])
                ->andFilterWhere(['like', 'semail', $this->semail])
                ->andFilterWhere(['like', 'country', $this->country])
                ->andFilterWhere(['like', 'websiteurl', $this->websiteurl])
                ->andFilterWhere(['like', 'birthday', $this->birthday])
                ->andFilterWhere(['like', 'groupname', $this->groupname]);

        return $dataProvider;
    }

Following is the code for the ContactsController no change just gii generated code

public function actionIndex()
    {
        $searchModel = new ContactsSearch();
      
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
    
        return $this->render('index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }

Following is the code for the gridview

GridView::widget([
        'dataProvider' => $dataProvider,
        'filterModel' => $searchModel,
        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],
            [
                'label' => 'First Name',
                'attribute' => 'firstname',
            ],
            [
                'label' => 'Last Name',
                'attribute' => 'lastname',
            ],
            //  'company',
            // 'address:ntext',
            // 'phone',
            // 'mobile',
            // 'fax',
    //Following is the related column from the groups table
            [
                'label' => 'Groups',
                'format' => 'ntext',
                'attribute'=>'groupname',
                'value' => function($model) {
                    foreach ($model->groups as $group) {
                        $groupNames[] = $group->groupname;
                    }
                    return implode("\n", $groupNames);
                },
            ],
            [
                'label' => 'Primary Email',
                'attribute' => 'pemail',
            ],
            // 'semail:email',
            // 'country',
            // 'websiteurl:url',
            // 'gender',
            // 'birthday',
            // 'status',
            // 'sentstatus',
            // 'addeddate',
            // 'updateddate',
            ['class' => 'yii\grid\ActionColumn'],
        ],
    ]);
    ?>

In this way you can show the related groupname in the contacts model with sorting and searching facility.

Thanks

]]>
0