แก้ปัญหา gem install bundler ไม่ผ่านติด permission

เนื่องจากงานที่ทำเป็นงานที่ต้องใช้ drupal ร่วมกับ theme เดิมที่มีคนพัฒนาไว้อยู่แล้ว env หลายอย่างถูกพัฒนาขึ้นไปอย่างมาก

By the moment, the last stable versions I’ve tested of each gem and that work together are:

WORKS

breakpoint (2.0.7)
compass (0.12.3)
sass (3.2.14)
susy (2.0.0.alpha.4)
zen-grids (1.4)
STILL NOT WORK

breakpoint (2.4.1)
compass (1.0.0.alpha.18)
sass (3.3.2)
susy (2.0.0)
zen-grids (2.0.0.beta.2)

To get the install command for each gem, and know each dependencies and versions:

Example SASS https://rubygems.org/gems/sass/

Some more info about deprecated browser legacy support method: http://www.atendesigngroup.com/blog/new-browser-support-features-compass-1x

https://www.drupal.org/node/2188263#comment-8567655

แต่จำเป็นต้องใช้ของเก่า ตามรายละเอียดด้านบน ซึ่งในระบบติดตั้ง bundler ไว้ ซึ่งสามารถช่วยให้ติดตั้ง gem versions เก่าได้ในครั้งเดียวเมื่อใช้คำสั่ง

$ <strong>bundle install</strong>
Fetching gem metadata from https://rubygems.org/............
Fetching version metadata from https://rubygems.org/..
Fetching dependency metadata from https://rubygems.org/.
Installing chunky_png 1.3.4
Installing fssm 0.2.10
Installing sass 3.2.14
Using bundler 1.14.6
Installing compass 0.12.3
Installing sass-globbing 1.1.1
Installing zen-grids 1.4
Installing breakpoint 2.0.7
Installing sassy-buttons 0.2.6
Installing susy 2.0.0.alpha.4
Bundle complete! 7 Gemfile dependencies, 10 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.

$ bundle show compass
/Users/evolution/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/compass-0.12.3

แต่ bundler ต้องติดตั้งโดยไม่ผ่าน permission ถึงจะไม่มีปัญหาตามมา เลยทำให้ตองแก้ตามนี้

https://stackoverflow.com/questions/29932409/bundle-command-not-found-mac/32190234


Just reiterating that for those (at least on OSX) for whom

gem install bundler

Gives a permissions error, an option that seems to have worked for many people is to use rbenv, which kind of adds a shim between your ruby commands (like gem install) and your environment (if my understanding is correct).

Definitely check out this answer.

The process is laid out fairly well under the above link. I chose to install via homebrew:

brew update
brew install rbenv

Then you have to add an argument command to your profile, which if you’re using the common ~/.bash_profile, can be done with:

echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

Which it looks like is adding a command to initialize rbenv via your shell.

Don’t for get to start a new shell, possibly by opening a new terminal or using the source ~/.bash_profile command.

Make sure your $PATH has this .rbenv/shims BEFORE any other directory where your shell might be looking for Ruby (OSX comes with it’s own version that we don’t want to fiddle with): echo $PATH.

which ruby
/Users/mikekilmer/.rbenv/shims/ruby
#GOOD!

Now install a version of Ruby:

rbenv install 2.2.3 

(See all possible versions with rbenv install -l).

Now we can use rbenv global 2.2.3 to switch to a use the newer version of Ruby globally. (Hmm. I thought we didn’t want to mess with the system version.) You could also try it with rbenv local 2.2.3 or rbenv shell 2.2.3.

Finally run:

rbenv rehash

Now ruby -v should return 2.2.3 and gem install bundler should work.

Did here.

Drupal 7: Creating custom modules

การตั้งชื่อ(short name) module ใน drupal 7 ใช้ในไฟล์ทั้งหมดและ ชื่อ function ใน module

  • ต้องขึ้นต้นด้วยตัวอักษร
  • เป็นตัวอักษรตัวเล็กทั้งหมดและ underscore เท่านั้น
  • ** ห้ามใช้ตัวอักษรตัวใหญ่ในการตั้งชื่อ(short name)

ตัวอย่างเช่น “current_posts”

Drupal จะเข้าใจ function ที่มี prefix เหมือนกันใน module file เท่านั้น
ที่สำคัญต้องแน่ใจว่าไม่มี module ที่มีชื่อซ้ำกันในทุก theme ที่ใช้งานในเว็บ

สร้าง folder และ module file

ให้ตั้งชื่อว่า “current_posts”

  1. เริ่มสร้าง module โดยสร้าง folder ใน Drupal ที่ติดตั้งไว้ตาม path นี้
    • sites/all/modules/current_posts In Drupal 6.x and 7.x  sites/all/modules ( หรือ sites/all/modules/contrib และ sites/all/modules/custom) is the preferred place for non-core modules
    • sites/all/themes (or sites/all/themes/contrib and sites/all/themes/custom) for non-core themes.
    • sites/your-site-folder/modules ในกรณีที่เป็น multi-site Drupal
  2. สร้าง info ไฟล์สำหรับ module
    • สร้างไฟล์ “current_posts.info” ใน path “sites/all/modules/current_posts”
    • อย่างน้อยที่สุด ในไฟล์ต้องการ ตามนี้
      name = Current Posts
      description = Description of what this module does
      core = 7.x
  3. สร้างไฟล์ “current_posts.module” ใน path “sites/all/modules/current_posts”
  4. เพิ่ม PHP Tag เปิดในไฟล์ “current_posts.module”

ตาม Coding standards แล้วให้ไม่ต้องปิดด้วย tag ?> (การใส่แท็กปิดอาจทำให้เกิดปัญหาเกี่ยวกับรันไทม์แปลก ๆ ในการตั้งค่าเซิร์ฟเวอร์บางอย่าง)

function ใน module ทั้งหมด จะใช้การตั้งชื่อ “hooks” ตามนี้ {modulename}_{functionname}
“functionname” จะเป็นชื่อต่อท้าย function ที่ถูกกำหนดไว้ล่วงหน้าแล้ว เพื่อให้ drupal สามารถรู้ได้ว่าเป็น hook อะไร


ไฟล์ info ใน module จะเป็นไฟล์ที่ กำหนดรายละเอียด (meta information) ของ module

general format จะมีรูปแบบตามนี้

name = Module Name
description = A description of what your module does.
core = 7.x

รายละเอียด metadata ในไฟล์ info ทั้งหมด: https://www.drupal.org/docs/7/creating-custom-modules/writing-module-info-files-drupal-7x


Concept ของ Hook ใน Drupal 7

ระบบ hook ของ Drupal ช่วยให้โมดูลสามารถโต้ตอบและแก้ไขข้อมูลของโมดูลอื่น ๆ ได้ (หรือแม้แต่ core ของ Drupal เอง) ข้อมูลเพิ่มเติม

การสร้าง Drupal 7 hook (และเรียกการใช้งาน)

การสร้าง hook และเรียกการใช้งาน สามารถทำได้โดยใช้หนึ่งในฟังก์ชั่นต่อไปนี้ (ไม่ใช่ทั้งหมดอันใดอันนึงเท่านั้น) drupal_alter(), module_invoke_all() and module_invoke()

Drupal 7 Hook Types:

ในทางปฏิบัติจะมี hook อยู่ 2 แบบที่คุณต้องได้ใช้งาน

  1. Alter hooks: เป็นวิธีปกติในการแก้ไขเนื้อหาของวัตถุหรือตัวแปรเฉพาะโดยรับตัวแปรใน hook โดยการอ้างอิง ปกติแล้วจะใช้ drupal_alter()
  2. Intercepting hooks: ทำให้ external module สามารถทำงานได้ แต่ไม่สามารถรับค่าตัวแปรแบบ by reference ได้ ปกติใช้งาน module_invoke_all() and module_invoke()

ตัวอย่างการใช้งาน

Example #1 (Simple Invoking)

// Calling all modules implementing 'hook_name':
module_invoke_all('hook_name');

Example #2 (Invoking a Particular one)

// Calling a particular module's 'hook_name' implementation:
module_invoke('module_name', 'hook_name');
// @note: module_name comes without '.module'
// @note: hook_name is the specific hook defined in that module

Example #3 (Collecting results in an array)

$result = array();
foreach (module_implements('hook_name') as $module) {
// Calling all modules implementing hook_hook_name and
// Returning results than pushing them into the $result array:
$result[] = module_invoke($module, 'hook_name');
}

Example #4 (Altering data using drupal_alter())

$data = array(
'key1' =&gt; 'value1',
'key2' =&gt; 'value2',
);
// Calling all modules implementing hook_my_data_alter():
drupal_alter('my_data', $data);
// You should implement hook_my_data_alter() in all other modules in which you want to alter $data

Example #5 (passing by reference: cannot use module_invoke())
<code>// @see user_module_invoke()
foreach (module_implements('hook_name') as $module) {
$function = $module . '_hook_name';
// will call all modules implementing hook_hook_name
// and can pass each argument as reference determined
// by the function declaration
$function($arg1, $arg2);
}</code>

Comments ใน Drupal modules

จะอยู่ใน format

 

/**
* @file
* A block module that displays recent blog and forum posts.
*/

รายชื่อ hook ในที่สามารถใช้งานได้

ในการเรียกใช้งาน hook_help() สามารถเรียกใช้งานโดยเรียก current_posts_help() ในไฟล์ “current_posts.module”

function current_posts_help($path, $arg) {

}

The $path parameter provides context for the help: where in Drupal or the module the user is when they are accessing help. The recommended way to process this variable is with a switch statement. This code pattern is common in Drupal modules. Here is an abbreviated implementation of this function for your module, along with its doc block comment:

/**
* Implements hook_help().
*
* Displays help and module information.
*
* @param path
* Which path of the site we're using to display help
* @param arg
* Array that holds the current path as returned from arg() function
*/
function current_posts_help($path, $arg) {
switch ($path) {
case "admin/help#current_posts":
return t("Displays links to nodes created on this date");
break;
}
}

switch statement ใช้เพื่อเฉพาะเจาะจงว่าให้แสดงเฉพาะ admin/help#current_posts

เรื่อง Localization API ดูรายละเอียดเพิ่มเติมได้ที่ Localization API


.install ไฟล์ใน Drupal 7

Drupal 7 ใช้ .install ไฟล์เพื่อ create database tables, fields และ insert data รวมไปถึงการ update โครงสร้าง database และ content ภาพใน table

ถ้าใน module มี _install() function จะถูกเรียกใช้งานเมื่อเปิดใช้งานเป็นครั้งแรก ปกติแล้วจะใช้เพื่อสร้างตารางที่จำเป็นใน module

ในการสร้างตารางจะใช้ Schema API Schema API จะใช่ในการกำหนดโครงสร้างตารางโดยใช้ array โดยมี API function สำหรับ creating, dropping, and changing tables, columns, keys, และ indexes

ตัวอย่างโครงสร้าง schema data (นำมาจาก Schema Api Documentation)

ตัวอย่าง schema ของตาราง “node”

$schema['node'] = array(
'description' =&gt; 'The base table for nodes.',
'fields' =&gt; array(
'nid' =&gt; array(
'description' =&gt; 'The primary identifier for a node.',
'type' =&gt; 'serial',
'unsigned' =&gt; TRUE,
'not null' =&gt; TRUE),
'vid' =&gt; array(
'description' =&gt; 'The current {node_revisions}.vid version identifier.',
'type' =&gt; 'int',
'unsigned' =&gt; TRUE,
'not null' =&gt; TRUE,
'default' =&gt; 0),
'type' =&gt; array(
'description' =&gt; 'The {node_type} of this node.',
'type' =&gt; 'varchar',
'length' =&gt; 32,
'not null' =&gt; TRUE,
'default' =&gt; ''),
'title' =&gt; array(
'description' =&gt; 'The title of this node, always treated a non-markup plain text.',
'type' =&gt; 'varchar',
'length' =&gt; 255,
'not null' =&gt; TRUE,
'default' =&gt; ''),
),
'indexes' =&gt; array(
'node_changed' =&gt; array('changed'),
'node_created' =&gt; array('created'),
),
'unique keys' =&gt; array(
'nid_vid' =&gt; array('nid', 'vid'),
'vid' =&gt; array('vid')
),
'primary key' =&gt; array('nid'),
);

การสร้างตาราง: hook_schema และ .install ไฟล์

สำหรับการใช้ Schema API ในการจัดการตารางของ module ซึ่งใน module ต้องมีไฟล์ .install เพื่อจัดการ hook_schema(), ตัวอย่างเช่น ไฟล์ mymodule.install ของ mymodule จะมี code

function mymodule_schema() {
$schema['mytable1'] = array(
// specification for mytable1
);
$schema['mytable2'] = array(
// specification for mytable2
);
return $schema;
}

หากเป็นการเข้าใช้งานครั้งแรกจะ hook_schema() จะถูกประกาศโดยอัตโนมัติ และถูกลบทิ้งไปเมื่อ uninstall module

hook_install() จะถูกเรียกใช้งานก่อนเป็นอันดับแรก เพื่อติดตั้งตาราง และ hook_uninstall() จะถูกเรียกตามมา เมื่อมีการ uninstall module

การ update module จะใช้ hook_update_N

ในการ update module จะใช้ functions hook_update_N (รายละเอียด API)

สมมติว่าเพิ่มคอลัมน์ใหม่ชื่อ ‘newcol’ เพื่อตามราง mytable1 ขั้นแรกตรวจสอบให้แน่ใจว่าได้อัปเดตโครงสร้าง schema ใน mymodule_schema () เพื่อให้ตารางที่สร้างขึ้นใหม่ได้คอลัมน์ใหม่ จากนั้นเพิ่มฟังก์ชันการอัพเดตใน mymodule.install:

function mymodule_update_1() {
db_add_field('mytable1', 'newcol', array('type' =&gt; 'int'));
}

นอกจากนี้ยังมีโมดูลที่เรียกว่า Schema Module ซึ่งมีฟังก์ชันเพิ่มเติมเกี่ยวกับ Schema ที่ไม่ได้ให้มาจาก Schema API หลักที่เป็นประโยชน์สำหรับนักพัฒนาโมดูล ในปัจจุบันนี้รวมถึง:

  • Schema documentation: hyperlinked display of the schema’s embedded documentation explaining what each table and field is for.
  • Schema structure generation: the module examines the live database and creates Schema API data structures for all tables that match the live database.
  • Schema comparison: the module compares the live database structure with the schema structure declared by all enabled modules, reporting on any missing or incorrect tables.

นอกจากนี้ยังมีโมดูลที่เรียกว่า Schemadata ซึ่งมีหน้าที่แสดงตาราง mysql และข้อมูลทั้งหมด โมดูลนี้มีประโยชน์สำหรับนักพัฒนาซอฟต์แวร์เพื่อประหยัดเวลา

ในการ replace Field

มีหลายกรณีไปดูเองที่ https://api.drupal.org/api/drupal/7.x/search/hook_field_

White screen of death

ในกรณีที่เกิด White screen of death สามารถดูปัญหาที่อาจเกิดขึ้นได้ที่ Show all errors while developing.


Declaring the block

ใน Drupal 7 จะมีอย่างน้อย 8 block hook สำหรับการแสดงผลแต่ละจุดในเว็บ เราจะใช้ function hook_block_info เพื่อให้ข้อมูล Drupal เพื่อให้ module แสดงผลในรายการ block

ในการใช้งาน hook นี้ในการกำหนด block ให้เข้าไปที่ current_posts.module และสร้าง function current_posts_block_info() ตามนี้

/**
* Implements hook_block_info().
*/
function current_posts_block_info() {
$blocks['current_posts'] = array(
// The name that will appear in the block list.
'info' =&gt; t('Current posts'),
// Default setting.
'cache' =&gt; DRUPAL_CACHE_PER_ROLE,
);
return $blocks;
}

(จำไว้เสมอว่าไม่ต้องปิด Tag ?> ใน code)

การตรวจสอบ

ให้ไปที่ Modules click ที่ checkbox เพื่อ enable “Current Posts” และ click ที่ “Save configuration” ต่อจากนั้นให้ไปที่ Structure > Blocks เลื่อนลงไปที่ด้านล่างของรายการ ในกลุ่ม disabled blocks ให้หาชื่อ ‘Current posts’ ถ้าหาก disable module ในหน้า Modules จะต้องไม่เห็นรายการใน list


การเรียกใช้ข้อมูลใน DB

หัวข้อหลักที่อธิบาย: Database API, ฟังก์ชั่นหลักอธิบาย: db_select()

ต่อไปเราจะสร้างฟังก์ชันที่กำหนดเองเพื่อเรียกค้นโพสต์ล่าสุด เมื่อโหนดถูกสร้างขึ้นครั้งแรกเวลาที่สร้างจะถูกเก็บไว้ในฐานข้อมูล เราจะใช้ฟิลด์ฐานข้อมูลนี้เพื่อค้นหาข้อมูลของเรา

เราจะเรียกใช้ function current_posts_contents ซึ่งเรายังคงทำตามแนวทางการตั้งชื่อโดยจะเริ่มต้นด้วย module short name ก่อนเสมอ จากนั้นเราจะใช้ชื่ออธิบายที่ไม่ใช่ Drupal hook

function นี้จะเริ่มต้นด้วยการหาตัวเลขเวลา (function ยังไม่จบนะ)

/**
* Custom content function.
*
* Set beginning and end dates, retrieve posts from database
* saved in that time period.
*
* @return
* A result set of the targeted posts.
*/
function current_posts_contents(){
//Get today's date.
$today = getdate();
//Calculate the date a week ago.
$start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);
//Get all posts from one week ago to the present.
$end_time = time();

code นี้จะหาเวลาปัจจุบัน จากนั้นจะคำนวนหาเวลาออกมาเป็นวินาทีสำหรับ 1 อาทิตย์ที่ผ่านมา โดยใช้ function mktime และ time() สำหรับ $end_time

ต่อจากนั้นเราจะใช้ Drupal’s Database API แสดง list ของข้อมูล

//Use Database API to retrieve current posts.
$query = db_select('node', 'n')
-&gt;fields('n', array('nid', 'title', 'created'))
-&gt;condition('status', 1) //Published.
-&gt;condition('created', array($start_time, $end_time), 'BETWEEN')
-&gt;orderBy('created', 'DESC') //Most recent first.
-&gt;execute();
return $query;
}

code เมื่อรวมกันแล้ว

/**
* Custom content function.
*
* Set beginning and end dates, retrieve posts from database
* saved in that time period.
*
* @return
* A result set of the targeted posts.
*/
function current_posts_contents(){
//Get today's date.
$today = getdate();
//Calculate the date a week ago.
$start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);
//Get all posts from one week ago to the present.
$end_time = time();

//Use Database API to retrieve current posts.
$query = db_select('node', 'n')
-&gt;fields('n', array('nid', 'title', 'created'))
-&gt;condition('status', 1) //Published.
-&gt;condition('created', array($start_time, $end_time), 'BETWEEN')
-&gt;orderBy('created', 'DESC') //Most recent first.
-&gt;execute();
return $query;
}

Generating block content

อธิบาย Drupal hook: hook_block_view()
function หลักที่ใช้: user_access(), l(), theme()

ขั้นตอนต่อไปในส่วนนี้คือนำข้อมูลที่เราสร้างขึ้นใน custom function ของเราและเปลี่ยนเป็นเนื้อหาสำหรับ block ซึ่งเราจะใช้ hook_block_view function นี้จะ return ค่า 2 ค่า คือ ‘subject’ คือ title ของ block และ ‘content’ คือ เนื้อหาของตัวมันเอง โดยใน function นี้จะมี switch คอยทำหน่าที่ กรอง โดยจะใช้ตัวแปร $delta ( function hook_block_view จะต้องมีตัวแปร $delta เสมอ )

Access check

ส่วนแรกของ code

function current_posts_block_view($delta = '') {
switch ($delta) {
case 'current_posts':
$block['subject'] = t('Current posts');
if (user_access('access content')) {
// Retrieve and process data here.
}

code ส่วนนี้จะเป็นการกำหนดว่า user ที่มี permission ตามที่ระบุเท่านั้นที่สามารถเข้าถึงส่วนนี้ได้ หากต้องการดูว่ามี permission อะไรบ้างให้เข้าไปดูได้ที่ People > List หรือ http://example.com/admin/people จะอยู่ใน permission dropdown

Coding the data as links

// Use our custom function to retrieve data.
$result = current_posts_contents();
// Array to contain items for the block to render.
$items = array();
// Iterate over the result set and format as links.
foreach ($result as $node) {
$items[] = array(
'data' =&gt; l($node-&gt;title, 'node/' . $node-&gt;nid),
);
}

ส่วนนี้ของ code จะใช้ตัวแปร $result รับค่าจาก current_posts_contents() เพื่อสร้างลิ้งแล้วนำไปเก็บใน array $items
function l() เป็น function ที่ใช้สำหรับสร้างลิ้ง (‘L’ ตัวพิมพ์เล็ก), parameter ตัวแรกคือ text ในลิ้ง parameter ตัวที่สอง คือ path ของลิ้ง

Theming the data

การทำงานของ Drupal จะมีการทำงานแบบ pluggable โดยแบ่งออกเป็นเลเยอร์

ส่วนสุดท้ายของ code สำหรับ current_posts_block_view:

// No content in the last week.
if (empty($items)) {
$block['content'] = t('No posts available.');
}
else {
//Pass data through theme function.
$block['content'] = theme('item_list', array('items' =&gt; $items));
}
}
return $block;
}

}

ถ้า $items มีข้อมูลตามเงื่อนไข จะไปทำงานต่อที่ theme() function ซึ่งใน argument แรกของ theme hook function นี้ของ Drupal มี theme hook เริ่มต้นหลายตัวที่สามารถใช้กับฟังก์ชันนี้ได้ ดูได้ที่ Default theme implementations ถ้าดูตาม code ด้านบนจะเป็นการกำหนดให้ข้อมูลของเราเป็น list รายการที่ไม่เรียงลำดับ

การใช้งาน function theme_item_list ของ theme hook จะมี argument ตัวที่ 2 เป็นการส่งค่า content เข้าไปใน theme

Code function นี้ทั้งหมด

/**
* Implements hook_block_view().
*
* Prepares the contents of the block.
*/
function current_posts_block_view($delta = '') {
switch ($delta) {
case 'current_posts':
$block['subject'] = t('Current posts');
if (user_access('access content')) {
// Use our custom function to retrieve data.
$result = current_posts_contents();
// Array to contain items for the block to render.
$items = array();
// Iterate over the resultset and format as links.
foreach ($result as $node) {
$items[] = array(
'data' =&gt; l($node-&gt;title, 'node/' . $node-&gt;nid),
);
}
// No content in the last week.
if (empty($items)) {
$block['content'] = t('No posts available.');
}
else {
// Pass data through theme function.
$block['content'] = theme('item_list', array(
'items' =&gt; $items));
}
}
return $block;
}

}

ส่วนที่เกี่ยวข้อง


Preparing for a module configuration form

 

อธิบายเกี่ยวกับ: hook_menu()

Registering the URL

ในส่วนนี้เราจะใช้ hook_menu() ถึงจะชื่อว่า hook_menu แต่มันไม่ได้แค่จัดการ menu เท่านั้น เรายังใช้มันในการลงทะเบียน path ในการเข้าถึงของแต่ละ URl ด้วย

Access check

hook_menu () ยังให้ความสำคัญกับความปลอดภัยของ Drupal เนื่องจากจะดำเนินการตรวจสอบการเข้าถึงของผู้ใช้ เราต้องการให้ผู้ดูแลระบบเพียงรายเดียวเท่านั้นที่สามารถเข้าถึงแบบฟอร์มนี้ได้และเราจะตรวจสอบสิทธิ์ใน hook_menu () เพื่อลดจำนวนสิทธิ์ที่ผู้ดูแลระบบต้องจัดการเราจะใช้สิทธิ์การดูแลระบบหลักแทนการสร้างสิทธิ์แบบกำหนดเองใหม่

ในระบบเมนูของ Drupal จะมีการแปลแอตทริบิวต์ ‘title’ และ ‘description’ อัตโนมัติ ซึ่งต้องใช้ฟังก์ชัน t() ในในการตัวอักษรสตริงทั้งหมด

/**
 * Implements hook_menu().
 */
function current_posts_menu() {
  $items = array();

  $items['admin/config/content/current_posts'] = array(
    'title' =&gt; 'Current posts',
    'description' =&gt; 'Configuration for Current posts module',
    'page callback' =&gt; 'drupal_get_form',
    'page arguments' =&gt; array('current_posts_form'),
    'access arguments' =&gt; array('access administration pages'),
    'type' =&gt; MENU_NORMAL_ITEM,
  );

  return $items;
}

เพิ่มปุ่มกำหนดค่าในหน้า Modules

ในไฟล์ current_posts.info ของคุณเพิ่มบรรทัดต่อไปนี้เพื่อสร้างปุ่มที่เชื่อมโยงไปยังหน้าการกำหนดค่าของคุณในหน้าโมดูล

name = Current Posts
description = A block module that lists links to recent posts.
core = 7.x

; NEW LINE
configure = admin/config/content/current_posts

Declaring the form

“page callback” เป็นการบอก Drupal ว่าอะไรคือสิ่งที่ลิ้งนี้ต้องการ ในที่นี้คือ “drupal_get_form”
“page arguments” เป็นค่าที่ส่งผ่านไปที่ function ตอนนี้คือ “current_posts_form” เรากำหนดว่าเป็นทั้ง ID ของฟอร์มและชื่อของฟังก์ชันที่จะสร้างฟอร์มการตั้งค่าของเรา โดยชื่อ function ที่เรากำหนดจะเป็นไปตาม naming convention ของ PHP variable ซึ่งต้องขึ้นต้นด้วย ชื่อ module ตามด้วย underscore


Creating the configuration form

ส่วนนี้เกี่ยวกับ: Form API
function หลักเกี่ยวกับ: variable_get(), system_settings_form()

ต่อไปเราจะสร้าง current_posts_form() function เราสร้างฟอร์มด้วยการเพิ่ม elements ลงใน array ของตัวแปร $form ใน array แต่ละ key จะมี hash mark (#)

เพิิ่ม code นี้ลงในไฟล์ current_posts.module

/**
 * Page callback: Current posts settings
 *
 * @see current_posts_menu()
 */
function current_posts_form($form, &amp;$form_state) {
  $form['current_posts_max'] = array(
    '#type' =&gt; 'textfield',
    '#title' =&gt; t('Maximum number of posts'),
    '#default_value' =&gt; variable_get('current_posts_max', 3),
    '#size' =&gt; 2,
    '#maxlength' =&gt; 2,
    '#description' =&gt; t('The maximum number of links to display in the block.'),
    '#required' =&gt; TRUE,
  );

  return system_settings_form($form);
}

Form element attributes ดูรายละเอียด Form API ดูได้ที่ Form API Reference

System settings

Drupal ช่วยให้เราสามารถบันทึกข้อมูลของฟอร์มด้วยฟังก์ชัน system_settings_form() โดยการใช้ฟังก์ชันในโค้ดของเราเราจะบอก Drupal ให้ส่งปุ่มและบันทึกข้อมูลลงในตัวแปรถาวรโดยใช้ variable_set() นอกจากนี้ยังจะมีข้อความยืนยันสีเขียวเมื่อบันทึกข้อมูลสำเร็จและข้อความแสดงข้อผิดพลาดสีแดงหากมีบางอย่างผิดพลาด หากต้องการคุณสามารถสร้างฟังก์ชันการส่งได้เองได้ (ดู Form API Quickstart Guide) แต่ตอนนี้เราจะใช้ฟังก์ชันนี้

Editing the query

เราต้องเพิ่มโค้ดสองบรรทัดลงใน query function current_posts_contents ส่วนแรกจะรับค่าจาก variable_get() มาเก็บไว้ที่ $max_num อีกส่วนจะเป็นการนำไปใช้ใน query (ดูตรงที่ comment ว่า NEW LINE)

function current_posts_contents() {
  //Get today's date.
  $today = getdate();
  //Calculate midnight a week ago.
  $start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);
  //Get all posts from one week ago to the present.
  $end_time = time();

 //NEW LINE 
 $max_num = variable_get('current_posts_max', 3);

  //Use Database API to retrieve current posts.
  $query = db_select('node', 'n')
    -&gt;fields('n', array('nid', 'title', 'created'))
    -&gt;condition('status', 1) //Published.
    -&gt;condition('created', array($start_time, $end_time), 'BETWEEN')
    -&gt;orderBy('created', 'DESC') //Most recent first.
    -&gt;range(0, $max_num) //NEW LINE
    -&gt;execute();
  return $query;
}

การใช้ variable_get() เราจะ save ค่า configuration setting เข้าไปที่ $max_num โดยจะมีค่า default คือ 3 จากนั้นจะเพิ่ม method range ลงไปใน query

ลองทดสอบ
เริ่มจาก disable และ enable module “current_posts” หลังจากนั้นให้ clear cache สำหรับ menu ระบบของ Drupal จะ recognize URL ใหม่ทั้งหมด
สำหรับการ clear cache สำหรับ menu ให้ไปที่ Configuration > Performance หรือ http://example.com/admin/config/development/performance จากนั้นคลิกที่ปุ่ม Clear all caches

ตอนนี้คุณสามารถทดสอบ settings form ได้แล้ว, ให้ไปที่ Configuration > Content authoring > Current posts หรือ http://example.com/admin/config/content/current_posts ให้ลองกำหนดค่าจำนวนลิ้งที่ต้องการแสดงผล


Validating the data

ส่วนนี้เกี่ยวกับ: Form API
function หลักเกี่ยวกับ: _validate(), form_set_error()

Form API จะมี validation ไว้ให้แล้วด้วย แต่เราก็ยังสามารถสร้าง validation function เองได้ด้วย
validation function จะทำงานเหมือนกับ hook โดยมีการตั้งชื่อว่า current_posts_form_validate($form, &$form_state) (อย่าสับสนกับ hook_validate () ซึ่งเป็นส่วนนึงของ main hook)

ตัวแปล $form_state จะรับค่ามาแบบ passed by reference ตามที่ค่าที่ถูกส่งมาจาก form (default key อะไรบ้างที่สามารถใช้ได้ให้ไปดูที่ drupal_build_form())

เพิ่มฟังก์ชันนี้ลงในไฟล์ current_posts.module ของคุณ:

/**
 * Implements validation from the Form API.
 * 
 * @param $form
 *   A structured array containing the elements and properties of the form.
 * @param $form_state
 *   An array that stores information about the form's current state 
 *   during processing.
 */
function current_posts_form_validate($form, &amp;$form_state){
  $max_num = $form_state['values']['current_posts_max'];
  if (!is_numeric($max_num)){
    form_set_error('current_posts_max', t('You must enter a number for the maximum number of posts to display.'));
  }
  elseif ($max_num &lt;= 0){
    form_set_error('current_posts_max', t('Maximum number of posts to display must be positive.'));
  }
}

การกำหนด permission สำหรับ page

hook ที่เกี่ยวข้อง: hook_permission(), hook_menu()

ลองสร้าง custom permission โดยใช้ hook_permission() permissions hook นี้สามารถกำหนดค่าได้ที่ People > Permissions (tab), หรือ http://example.com/admin/people/permissions จะเป็นการ กำหนด role ของผู้ใช้ ว่า role ไหนบ้างจะมีสิทธิ์เข้าถึงหน้าเว็บที่เราจะสร้าง

เพิ่ม function นี้ลงในไฟล์ .module:

/**
 * Implements hook_permission().
 */
function current_posts_permission() {
  return array(
    'access current_posts content' =&gt; array(
      'title' =&gt; t('Access content for the Current posts module'),
    )
  );
}

Option ทั้งหมดที่สามารถใช้งานได้สามารถดูได้ที่ hook_permission()

ลงทะเบียน URL และการตั้งชื่อ page function

เราจะต้องแก้ไข current_posts_menu() ในการสร้าง path และชื่อของหน้าใหม่ โดยต้องตั้งชื่อตาม naming conventions ใน Drupal

  • หากคุณกำลังใช้งาน Drupal hook คุณต้องระบุชื่อฟังก์ชันเสมอ “your_module_name_hookname”
  • ถ้าฟังก์ชันของคุณไม่ใช่ Drupal hook แต่เป็นอย่างอื่นที่ public ให้ตั้งชื่อโดยมี “your_module_name_” ขึ้นก่อนแล้วตามด้วยชื่อฟังก์ชันของคุณ แต่ต้องแน่ใจว่าไม่ได้ซ้ำกันกับ Drupal hook
  • ถ้าคุณกำลังสร้าง private ฟังก์ชัน ให้เริ่มต้นชื่อฟังก์ชันด้วยเครื่องหมายขีดล่าง เช่น “_your_module_name_”
/**
* Implements hook_menu().
*/
function current_posts_menu() {
    $items = array();    
    $items['current_posts'] = array(
        'title' =&gt; 'Current posts',
        'page callback' =&gt; '_current_posts_page',
        'access arguments' =&gt; array('access current_posts content'),
        'type' =&gt; MENU_NORMAL_ITEM, //Will appear in Navigation menu.
      );
    return $items;
}

Adapting the query

ในตัวอย่างนี้จะเป็นการปรับการแสดงผล ให้เหมาะสมกับการใช้งานแต่ละแบบ เช่น ถ้าเป็น block ให้จำกัดจำนวนการแสดงผลตามที่กำหนดไว้ แต่ถ้าแสดงเป็น page ให้แสดงอีกแบบ

function current_posts_contents($display){   //$display argument is new.
  //Get today's date.
  $today = getdate();
  //Calculate midnight a week ago.
  $start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);
  //Get all posts from one week ago to the present.
  $end_time = time();
  
  $max_num = variable_get('current_posts_max', 3);
  
  //Use Database API to retrieve current posts.
  $query = db_select('node', 'n')
    ->fields('n', array('nid', 'title', 'created'))
    ->condition('status', 1) //Published.
    ->condition('created', array($start_time, $end_time), 'BETWEEN')
    ->orderBy('created', 'DESC'); //Most recent first. Query paused here.
 
   if ($display == 'block'){ 
  // Restrict the range if called with 'block' argument.
    $query->range(0, $max_num);
  } //Now proceeds to execute().
  //If called by page, query proceeds directly to execute().
  
  return $query->execute();
}

แก้ไขการใช้งานที่ current_posts_block_view

เพื่อให้ code นี้ใช้งานได้ให้ลองไปแก้ไข code ที่ function current_posts_block_view ให้เป็นแบบนี้ก่อน

$result = current_posts_contents('block');

จากนั้นลองทดสอบดู


Theming the page

เนื้อหานี้เกี่ยวกับ: Render API

ตอนนี้เราจะเขียนฟังก์ชันเพจที่เราสร้างขึ้นใน current_posts_menu()
นี่เป็นส่วนแรกของโค้ด:

/**
 * Custom page callback function, declared in current_posts_menu().
 */
function _current_posts_page() {
  $result = current_posts_contents('page');
  //Array to contain items for the page to render.
  $items = array();
  //Iterate over the resultset and format as links.
  foreach ($result as $node) {
    $items[] = array(
    'data' => l($node->title, 'node/' . $node->nid),
    ); 
  }

เราเรียกใช้ฟังก์ชัน query ด้วยอาร์กิวเมนต์ ‘page’ เพื่อดึงข้อมูลทั้งหมดที่เกี่ยวข้องออกจากฐานข้อมูล จากนั้นเราจะส่งผ่าน resultset เพื่อสร้างลิงก์สำหรับแต่ละโพสต์

Render array

ตอนนี้เราจะเจาะลึกเข้าไปในระบบธีมและจัดรูปแบบเอาต์พุตของเราเป็น render array, เมื่อใดก็ตามที่เป็นไปได้ Drupal 7 ข้อมูลที่ใช้ในการสร้างเพจจะถูกเก็บไว้เป็นอาร์เรย์ที่มีโครงสร้างจนถึงขั้นตอนการแสดงผลใน theming system ซึ่งจะช่วยให้โมดูลและโมดูลอื่น ๆ ของคุณสามารถใช้เนื้อหาเป็นข้อมูลได้นานที่สุดเท่าที่จะเป็นไปได้ในกระบวนการสร้างเพจ ดูคำอธิบายเพิ่มเติมเรื่อง Render Arrays in Drupal 7 ทั้งหมด

code ต่อจากส่วนแรก

if (empty($items)) { //No content in the last week.
    $page_array['current_posts_arguments'] = array(
      //Title serves as page subtitle
      '#title' => t('All posts from the last week'),
      '#markup' => t('No posts available.'),
    );
    return $page_array;  
  } 

Theme hook suggestion

นี่เป็นส่วนสุดท้ายของโค้ด:

else {
    $page_array['current_posts_arguments'] = array(
      '#title' => t('All posts from the last week'),
      '#items' => $items,
      //Theme hook with suggestion.  
      '#theme' => 'item_list__current_posts',
    );
    return $page_array;
  }
}

underscore 2 ตัวจะเป็นส่วนที่บอก Drupal ว่านี่คือ theme hook suggestion ซึ่งเป็นรูปแบบที่ Drupal เข้าใจ

เรื่อง theme hook suggestion มีเรื่องการทำงานของ underscore 2 ตัว เมื่อใส่เข้าไป drupal จะ… ไปอ่านต่อเอง


Adding a ‘More’ link

เนื้อหาหลักเกี่ยวกับ: Block system, Render arrays, Menu system
function หลักเกี่ยวกับ: drupal_set_title()

ล่าสุดที่เราเพิ่มเข้าไปใน module เราจะดึงสิ่งที่เราได้เรียนรู้เกี่ยวกับ block system, menu system, และ render arrays และการแก้ปัญหา minor bug ใน Drupal 7

เป็นไปได้ว่า คุณอาจไม่สามารถเข้าถึงเนื้อหานี้จาก ‘Navigation menu’ ไม่ได้ แต่ถ้ามีลิ้ง ‘More’ ที่ด้านล่างของ ‘Current posts’ block คุณอาจเข้าจากทางนี้แทน

ถ้าคุณย้อยกลับไปดู Default theme implementations reference ใน Generating block content จะเห็นว่ามี theme hook ที่ชื่อว่า theme_more_link เราจะใช้ function นี้ร่วมกับ theme hook suggestion ในการแสดง ‘More’ link.

Child render elements

เริ่มจากเปลี่ยนไป call theme_item_list ในการ render array ใน page function เราจะทำให้มันเป็น child ของ block[‘content’] ในการแสดง ‘More’ link ให้เข้าไปแก้ code ตามนี้ที่ current_posts_block_view

else {
  //Pass data through theme function.
  $block['content']['posts'] = array(
    '#theme' => 'item_list__current_posts__block',
    '#items' => $items,
  );

จากนั้นเพิ่มลิ้ง more เข้าไปที่ code

//Add a link to the page for more entries.
  $block['content']['more'] = array(
    '#theme' => 'more_link__current_posts',
    '#url' => 'current_posts',
    '#title' => t('See the full list of current posts.'),
  );
}

รวมๆ แล้วจะเป็นแบบนี้

/**
 * Implements hook_block_view().
 * 
 * Prepares the contents of the block.
 */
function current_posts_block_view($delta = '') {
  switch ($delta) {
    case 'current_posts':
      $block['subject'] = t('Current posts');
      if (user_access('access content')) {
        // Use our custom function to retrieve data.
        //$result = current_posts_contents();
        $result = current_posts_contents('block');

        // Array to contain items for the block to render.
        $items = array();
        // Iterate over the resultset and format as links.
        foreach ($result as $node) {
          $items[] = array(
            'data' => l($node->title, 'node/' . $node->nid),
          ); 
        }
       // No content in the last week.
        if (empty($items)) {
          $block['content'] = t('No posts available.');  
        } 
        else {
          // Pass data through theme function.
          /*$block['content'] = theme('item_list', array(
            'items' => $items));*/
          $block['content']['posts'] = array(
    		'#theme' => 'item_list__current_posts__block',
    		'#items' => $items,
  			);
          //Add a link to the page for more entries.
		  $block['content']['more'] = array(
		    '#theme' => 'more_link__current_posts',
		    '#url' => 'current_posts',
		    '#title' => t('See the full list of current posts.'),
		  );
        }
      }
    return $block;
  }
  
}

Android: Skip some fragments onBackPressed

There is many way can do.

—===================================—
Very simple!! When you are starting the activity C, from B, use B.finish(). Something like this.

Intent i = new Intent(B.this, C.class);
B.this.finish();
startActivity(i);

This will remove B from the stack!

—===================================—

Intent i = new Intent(B.this, C.class);
i.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(i);

—===================================—
Set a flag for B activity like this

private boolean mDestroyActivity = false;

set that flag true when you call startActivity C.

for activity B onStop method add checking like this:

if (mDestroyActivity) finish();

Then when you press back button in C you will jump back to A.

android: install sdkman and install gradle 3.3

$ curl -s https://get.sdkman.io | bash

Thanks for using...                                                              
                                                                                 
                                                                                 
     SSSSSSSSSSSSSSS DDDDDDDDDDDDD       KKKKKKKKK    KKKKKKK                  
   SS:::::::::::::::SD::::::::::::DDD    K:::::::K    K:::::K                  
  S:::::SSSSSS::::::SD:::::::::::::::DD  K:::::::K    K:::::K                  
  S:::::S     SSSSSSSDDD:::::DDDDD:::::D K:::::::K   K::::::K                  
  S:::::S              D:::::D    D:::::DKK::::::K  K:::::KKK                  
  S:::::S              D:::::D     D:::::D K:::::K K:::::K                     
   S::::SSSS           D:::::D     D:::::D K::::::K:::::K                      
    SS::::::SSSSS      D:::::D     D:::::D K:::::::::::K                       
      SSS::::::::SS    D:::::D     D:::::D K:::::::::::K                       
         SSSSSS::::S   D:::::D     D:::::D K::::::K:::::K                      
              S:::::S  D:::::D     D:::::D K:::::K K:::::K                     
              S:::::S  D:::::D    D:::::DKK::::::K  K:::::KKK                  
  SSSSSSS     S:::::SDDD:::::DDDDD:::::D K:::::::K   K::::::K                  
  S::::::SSSSSS:::::SD:::::::::::::::DD  K:::::::K    K:::::K                  
  S:::::::::::::::SS D::::::::::::DDD    K:::::::K    K:::::K                  
   SSSSSSSSSSSSSSS   DDDDDDDDDDDDD       KKKKKKKKK    KKKKKKK                  
                                                                               
                                                                               
                      mmmmmmm    mmmmmmm     aaaaaaaaaaaaa  nnnn  nnnnnnnn     
                    mm:::::::m  m:::::::mm   a::::::::::::a n:::nn::::::::nn   
                   m::::::::::mm::::::::::m  aaaaaaaaa:::::an::::::::::::::nn  
                   m::::::::::::::::::::::m           a::::ann:::::::::::::::n 
                   m:::::mmm::::::mmm:::::m    aaaaaaa:::::a  n:::::nnnn:::::n 
                   m::::m   m::::m   m::::m  aa::::::::::::a  n::::n    n::::n 
                   m::::m   m::::m   m::::m a::::aaaa::::::a  n::::n    n::::n 
                   m::::m   m::::m   m::::ma::::a    a:::::a  n::::n    n::::n 
                   m::::m   m::::m   m::::ma::::a    a:::::a  n::::n    n::::n 
                   m::::m   m::::m   m::::ma:::::aaaa::::::a  n::::n    n::::n 
                   m::::m   m::::m   m::::m a::::::::::aa:::a n::::n    n::::n 
                   mmmmmm   mmmmmm   mmmmmm  aaaaaaaaaa  aaaa nnnnnn    nnnnnn 
                                                                                                             
                                                                                                             
                                                 Now attempting installation...
                                                                               
Looking for a previous installation of SDKMAN...
SDKMAN found.

======================================================================================================
 You already have SDKMAN installed.
 SDKMAN was found at:

    /Users/tmac/.sdkman

 Please consider running the following if you need to upgrade.

    $ sdk selfupdate force

======================================================================================================


$source ~/.bash_profile
$sdk install gradle 3.3
$Gradle --version

------------------------------------------------------------
Gradle 3.3
------------------------------------------------------------

Build time:   2017-01-03 15:31:04 UTC
Revision:     075893a3d0798c0c1f322899b41ceca82e4e134b

Groovy:       2.4.7
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_102 (Oracle Corporation 25.102-b14)
OS:           Mac OS X 10.12.3 x86_64

Android: How to use onSavedInstanceState.

The Bundle is a container for all the information you want to save. You use the put* functions to insert data into it. Here’s a short list (there are more) of put functions you can use to store data in the Bundle.

putString
putBoolean
putByte
putChar
putFloat
putLong
putShort
putParcelable (used for objects but they must implement Parcelable)

In your onCreate function, this Bundle is handed back to the program. The best way to check if the application is being reloaded, or started for the first time is:

if (savedInstanceState != null) {
    // Then the application is being reloaded
}

To get the data back out, use the get* functions just like the put* functions. The data is stored as a name-value pair. This is like a hashmap. You provide a key and the value, then when you want the value back, you give the key and the function gets the value. Here’s a short example.

@Override
public void onSaveInstanceState(Bundle outState) {
   outState.putString("message", "This is my message to be reloaded");
   super.onSaveInstanceState(outState);
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        String message = savedInstanceState.getString("message");
        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
    }
}

Your saved message will be toasted to the screen. Hope this helps.

ref: http://stackoverflow.com/questions/6525698/how-to-use-onsavedinstancestate-example-please

Android: Fragment in ViewPager not restored after popBackStack

just change getActivity().getSupportFragmentManager() to getChildFragmentManager() when you init viewPagerAdapter

viewPager = (HeightWrappingViewPager) view.findViewById(R.id.viewpager);
viewPagerAdapter = new CheckListViewPagerAdapter(getChildFragmentManager()); //getActivity().getSupportFragmentManager()
viewPager.setAdapter(viewPagerAdapter);

ref: http://stackoverflow.com/questions/13379194/how-to-add-a-fragment-inside-a-viewpager-using-nested-fragment-android-4-2
https://code.google.com/p/android/issues/detail?id=55068

Android: Get Latitude and Longitude of the mobile device

With google things changes very often: non of the previous answers worked for me.

April 2016

based on this google training here is how you do it using

fused location provider

this requires Set Up Google Play Services

Activity class

 

public class GPSTrackerActivity extends AppCompatActivity implements
    GoogleApiClient.ConnectionCallbacks,     
 GoogleApiClient.OnConnectionFailedListener {

private GoogleApiClient mGoogleApiClient;
Location mLastLocation;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (mGoogleApiClient == null) {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

}

protected void onStart() {
    mGoogleApiClient.connect();
    super.onStart();
}

protected void onStop() {
    mGoogleApiClient.disconnect();
    super.onStop();
}

@Override
public void onConnected(Bundle bundle) {
    try {

        mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
                mGoogleApiClient);
        if (mLastLocation != null) {
            Intent intent = new Intent();
            intent.putExtra("Longitude", mLastLocation.getLongitude());
            intent.putExtra("Latitude", mLastLocation.getLatitude());
            setResult(1,intent);
            finish();

        }
    } catch (SecurityException e) {

    }

}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {

}
}

usage

in you activity

Intent intent = new Intent(context, GPSTrackerActivity.class);
    startActivityForResult(intent,1);

And this method

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == 1){
        Bundle extras = data.getExtras();
        Double longitude = extras.getDouble("Longitude");
        Double latitude = extras.getDouble("Latitude");
    }
}

Ref: http://stackoverflow.com/questions/2227292/how-to-get-latitude-and-longitude-of-the-mobile-device-in-android

Android: Read/Write String From A File

Write File:

private void writeToFile(String data,Context context) {
    try {
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput("config.txt", Context.MODE_PRIVATE));
        outputStreamWriter.write(data);
        outputStreamWriter.close();
    }
    catch (IOException e) {
        Log.e("Exception", "File write failed: " + e.toString());
    } 
}

Read File:

private String readFromFile(Context context) {

    String ret = "";

    try {
        InputStream inputStream = context.openFileInput("config.txt");

        if ( inputStream != null ) {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String receiveString = "";
            StringBuilder stringBuilder = new StringBuilder();

            while ( (receiveString = bufferedReader.readLine()) != null ) {
                stringBuilder.append(receiveString);
            }

            inputStream.close();
            ret = stringBuilder.toString();
        }
    }
    catch (FileNotFoundException e) {
        Log.e("login activity", "File not found: " + e.toString());
    } catch (IOException e) {
        Log.e("login activity", "Can not read file: " + e.toString());
    }

    return ret;
}