() translation by (you can also view the original English article)



Ang tutorial na ito ay bahagi ngserye tungkol sa pagbuo ng iyong startup gamit ang PHP sa Envato Tuts+. Sa seryeng ito, gagabayan ko kayo sa paglulunsad ng isang startup mula sa konsepto sa kasalukuyan gamit ang aking Meeting Planner app bilang isang makatotohanan na halimbawa. Bawat hakbang sa kahabaan ng proseso, ibibigay ko ang open-source code ng aking Meeting Planner app bilang halimbawa kung saan maaari mong malaman ang pinagmulan. Tatalakayin ko din angmga isyu tungkol sa negosyo kung meron tayong madaanan.
Panimula
Magandang umaga. Ngayon, gagabayan ko kayo kung paano ko ginamit ang Google API para ihango ang mga kontak ko sa Tagaplano ng Pulong. Ang layunin ay para gawing mabilis para sa mga tao na imbitahan ang kanilang mga kaibigan sa mga pagpupulong.
Kapag hindi mo pa nasubukang mag-iskedyul ng pagpupulong gamit ang Tagaplano ng Pulong, mangyaring subukan ito. Kapag ginagamit mo ang iyong Google akawnt para mag-sign up, puwede mong bisitahin ang Mga Kaibigan na pahina sa itaas at Ihango ang Iyong Mga Google Kontak. Ibahagi ang iyong mga saloobin at katugunan sa mga puna sa ibaba.
Sumasali ako sa mga talakayan, pero puwede
rin kayong makipagugnayan sa akin @reifman sa Twitter (kamakailan lamang ang aking akawnt ay
naberika na kaya kasing kalog ko na si Justin Beebert (puna para sa mga
editorial na diyos—Tiwala ako sa ganitong pagbabaybay. Sa tingin ko tama. Iwanan na.) Lagi akong
bukas sa mga bagong tampok na mga ideya para sa Tagaplano ng Pulong ganon din
sa mga mungkahi para sa mga darating na
mga serye ng episodyo.
Bilang paalala, ang lahat ng mga code para sa Meeting Planner ay nakasulat sa Yii2 Framework para sa PHP. Kung gusto mong matuto nang iba pa tungkol sa Yii2, tingnan ang aming parallel series Programming Sa Yii2.
Nagiisip Tungkol sa Integrasyon ng Mga Google Kontak
Ang Pahina Ng Mga Kaibigan
Maraming mga tao ang may libong mga kontak sa kanilang Google akawnt—at ilan ay importante sa kanila. Pero, para sa karamihan, walang paraan para malaman kung alin ang importante at alin ang hindi.
Naniniwala ako na ang sukat ng talahanayan ng Gumagamit sa Tagaplano ng Pulong ay may epekto sa pangkalahatang pagsasagawa ng serbisyo. Ayaw kong maghango ng mga kontak na walang kaugnayan sa talahanayan ng Gumagamit.
Lumikha ito ng ilang komplikasyon sa parehong UX at kowd kung saan tumitingin ang mga tao para i-access ang kanilang mga kaibigan sa serbisyo.
Napagpasyahan ko sa huli na lumikha ng hiwalay na talahanayan para sa mga kontak at aktwal na ipakita ito nang hiwalay sa interface ng gumagamit para sa ngayon.



Pagpili ng mga Kalahok para sa mga Pulong
Kung saan ito patungo ay magiging madali para sa mga tao na magdagdag ng mga kaibigan mula sa kanilang mga kontak sa pamamagitan ng pagmakinilya ng ilan sa mga naunang karakter. Gumagamit ako ng Typeahead na widget sa Magdagdag ng mga Kalahok na pop-up na ipinakita sa ibaba:



Pagkatapos kong maihango ang mga Google Kontak ko, sila ay isinasama sa aking mga kaibigan (mga taong naimbitahan ko sa pulong o naimbitahan ng).
Sa kasong ito, sinimulan kong magmakinilya ng sar at isang buong pangkat ng Sar-unlapi na mga pangalan ang nagpakita:



Paghahanap ng kahit sino para imbitahan sa pulong mula sa iyong mga Google Kontak ay naging mabilis at madali na (hanggang sa magdagdag ka ng marami sa kanila, na nabanggit ko pa sa ibaba).
Mga Isyu sa Pagkapribado
Ayaw ko ring abusuhin ang tiwala ng mga tao sa pamamagitan ng maling paggamit ng libo ng kanilang mga Kontak. Sa oras na ito, hindi namin iaalok sa mga tao ang oportunidad na imbitahan lahat ng kanilang mga Google kontak sa Tagaplano ng Pulong, gayunman baka ialok namin ito sa hinaharap. Tiyak kami na hindi namin sila papadalhan ng sulatroniko nang walang permiso.
Pagsusulat ng Kowd
Kapag hindi mo pa, nasilip ang Pagtatayo ng Iyong Startup Gamit ang PHP: Pagpapadali ng Onramp Gamit ang OAuth. Iyan ang episodyo kung saan una kong pinatotohanan ang Google APIs para sa OAuth Login at Sign-up.
Maingat ang Google tungkol sa iyong seguridad gamit ang kanilang APIs. Dahil sa nangyari kamakailan sa mga Yahoo hack, lalo ko itong pinapahalagahan nang mas labis. Gayunman, ginagawa nitong mas mahirap ang kanilang APIs kumpara sa iba para patotohanan at pagtrabahuan.
Sa katunayan, nakita ko sa Google Kontak API na daloy ang ilan sa pinakanakakalito, nakakabigo at mahirap na isulat. At ang Google API’s ay hindi pabor sa mga PHP na programista—kami ang huling nakakakuha ng kowd na paparisan.
Simulan natin.
Paggawa ng Talahanayan para sa Adres
Dahil mayroon ng GumagamitKontak na talahanayan para sa telepono ng gumagamit at Skype na mga adres, napagpasyahan ko na tawagin ang talahanayan na Adres. Ito ang paglipat para gawin ito:
1 |
<?php
|
2 |
use yii\db\Schema; |
3 |
use yii\db\Migration; |
4 |
|
5 |
class m160904_001244_create_table_address extends Migration |
6 |
{
|
7 |
public function up() |
8 |
{
|
9 |
$tableOptions = null; |
10 |
if ($this->db->driverName === 'mysql') { |
11 |
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; |
12 |
}
|
13 |
|
14 |
$this->createTable('{{%address}}', [ |
15 |
'id' => Schema::TYPE_PK, |
16 |
'user_id' => Schema::TYPE_BIGINT.' NOT NULL', |
17 |
'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0', |
18 |
'firstname' =>Schema::TYPE_STRING.' NOT NULL', |
19 |
'lastname' =>Schema::TYPE_STRING.' NOT NULL', |
20 |
'fullname' =>Schema::TYPE_STRING.' NOT NULL', |
21 |
'email' =>Schema::TYPE_STRING.' NOT NULL', |
22 |
'created_at' => Schema::TYPE_INTEGER . ' NOT NULL', |
23 |
'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL', |
24 |
], $tableOptions); |
25 |
$this->addForeignKey('fk_address_user_id', '{{%address}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE'); |
26 |
}
|
27 |
|
28 |
public function down() |
29 |
{
|
30 |
$this->dropForeignKey('fk_address_user_id', '{{%address}}'); |
31 |
$this->dropTable('{{%address}}'); |
32 |
}
|
33 |
}
|
Siyempre, ginamit ko ang Yii's Gii para tulungan ako sa kontroler, modelo, at mga tingin. Ito ay natalakay na sa naunang serye ng startup.
Pagpapalawig ng Google API Pagpapatunay
Natatandaan mo yung Google Kredensyal na pahina sa tutoryal na nabanggit sa itaas:



Mahahanap mo ito mula sa Google Developers Console.
Kailangan mong magdagdag ng URLs para sa lahat ng iyong mga kapaligiran—pagbuo, pagtatanghal, produksyon, atbp.—at para sa bawat kontroler at paraan. Ginagawa nitong komplikado ang mga pagsisikap para magtrabaho gamit ang kanyang Kontak API, pero marahil mas mabuti sa pagsisiguro ng mga datos ng mga tao.



Paghango ng mga Google Kontak
Ito na ang Google Kontak API v3.0. Hindi ko na napansin kung kailan ako nagsimulang magsulat ng kowd ngayon nirerekomenda na nila ang Taong API para sa basa-lamang na access. Sa kasamaang palad, ang aking kowd ay gumagamit ng basa/sulat API. Okey, hindi ako henyo. Ang mga negosyante ay bihira—kahit si Bill Gates sabi niya nagkataon na maswerte siya.
Sa pangkalahatan, sa tingin ko Google
Kontak API ang isa sa mas nakakalito at mahirap na APIs na ginamit ko.
Kung mayroon akong mas mataas na antas ng kadalubhasaan sa Google API na pagbuo o naggugol ng mas maraming oras magtrabaho dito, baka may nakita akong mas simpleng paraan. Pero, mula sa kung ano ang maaari kong sabihin, importante na gawin mo lahat gamit ang API mula sa isang URL. Sa kaso ko https://meetingplanner.io/address/import.
At ibinabalik ni Google ang mga susi at dinidirekta ka pabalik sa URL na ito nang paulit-ulit—kaya kailangan mong bantayan ang estado ng API at nagtatrabaho dito.
Pinapalagay ko na lahat ito ay ginagawa para dagdagan ang seguridad, pero kailangan ng pangangasiwa ng estado na built-in para sa kung hindi man ay simpleng mga API na hiling. Ang pangagasiwa ng estado ay makakatipid ng oras, pero ito lamang ay kung ang dokumentasyon at halimbawang kowd ay mahusay. Sa kasong ito, para sa PHP, hindi sila.
Pagsisimula
Tingnan nating ang AddressController.php actionImport()
:
1 |
public function actionImport() { |
2 |
// imports contacts from the google api
|
3 |
$address = new Address(); |
4 |
// create session cookies
|
5 |
$session = Yii::$app->session; |
6 |
// if we request code reset, then remove the google_code cookie
|
7 |
// i.e. if google_code expires
|
8 |
if (isset($_GET['reset']) && !$session->has('google_code_reset')) { |
9 |
// prevent loops
|
10 |
$session->set('google_code_reset'); |
11 |
// reset the google_code
|
12 |
$session->remove('google_code'); |
13 |
$this->redirect(['import']); |
14 |
}
|
Sa itaas, tintingnan ko kung gusto ni Google i-reset ang kanyang API na mga token. Sa kasong ito, tinanggal ko ang mga cookie na naimbak na at idirekta ko pabalik sa paraan para magsimula ulit.
Paggawa ng Hiling para sa isang Token
Sa ibaba, gumagawa ako ng una kong hiling sa Google sa pamamagitan ng kanyang PHP librerya ng kliyente:
1 |
// always remove the reset request cookie
|
2 |
$session->remove('google_code_reset'); |
3 |
// build the API request
|
4 |
$redirect_uri=Url::home(true).'address/import'; |
5 |
$session->open(); |
6 |
$client = new \Google_Client(); |
7 |
$client -> setApplicationName('Meeting Planner'); |
8 |
$client -> setClientid( Yii::$app->components['authClientCollection']['clients']['google']['clientId']); |
9 |
$client -> setClientSecret(Yii::$app->components['authClientCollection']['clients']['google']['clientSecret']); |
10 |
$client -> setRedirectUri($redirect_uri); |
11 |
$client -> setAccessType('online'); |
12 |
$client -> setScopes('https://www.google.com/m8/feeds'); |
13 |
$googleImportUrl = $client -> createAuthUrl(); |
Ang Google PHP librerya ng kliyente ay nasa beta. Sa katunayan, ang PHP sa pangkalahatan ay nahuling isip lamang ng Google. Kaya hindi madaling magtrabaho sa PHP gamit ang kanilang APIs.
Pansinin sa itaas na ang Google's
$direktapabalik_uri
ay parehong paraan ulit: 'adres/hango
'.
Susunod, susubukan nating ilagay ang token mula sa tanong na parametro sa isang cookie:
1 |
// moves returned code to session variables and returns here
|
2 |
if (isset($_GET['code'])) |
3 |
{
|
4 |
$auth_code = $_GET['code']; |
5 |
$session->set('google_code',$auth_code); |
6 |
header('Location: '.Url::home(true).'address/import'); |
7 |
// do not remove - breaks the API
|
8 |
exit; // do not replace with yii app end |
9 |
// do not remove above exit
|
10 |
} else { |
11 |
$session_code = $session->get('google_code'); |
12 |
if (!isset($session_code)) { |
13 |
$this->redirect( $googleImportUrl); |
14 |
}
|
15 |
}
|
Kapag nakuha natin ang kowd mula sa Google, kailangan mong itakda ito sa cookie at idirekta muli sa pahina ulit. Iyan ay kakaiba sa akin.
Maligaya ako, napansin ko rin na kapag hindi ako gumawa ng loop dati noong nawawala ang kowd—para bumalik sa pahina ulit, hindi ito gagana nang naaalinsunod.
Pagkatapos, gagawa tayo at tatanungin ang Google na ipakita sa gumagamit ang permiso na dyalogo para bigyan ng Tagaplano ng Pulong ng access sa kanilang mga kontak:
1 |
if (isset($session_code)) { |
2 |
$auth_code = $session_code; |
3 |
$fields=array( |
4 |
'code'=> urlencode($auth_code), |
5 |
'client_id'=> urlencode(Yii::$app->components['authClientCollection']['clients']['google']['clientId']), |
6 |
'client_secret'=> urlencode(Yii::$app->components['authClientCollection']['clients']['google']['clientSecret']), |
7 |
'redirect_uri'=> urlencode($redirect_uri), |
8 |
'grant_type'=> urlencode('authorization_code'), |
9 |
);
|
10 |
// Requests the access token
|
11 |
$post = ''; |
12 |
foreach($fields as $key=>$value) |
13 |
{
|
14 |
$post .= $key.'='.$value.'&'; |
15 |
}
|
16 |
$post = rtrim($post,'&'); |
17 |
$result = $address->curl('https://accounts.google.com/o/oauth2/token',$post); |
18 |
$response = json_decode($result); |
19 |
if (isset($response->error)) { |
20 |
if ($response->error_description == 'Code was already redeemed.') { |
21 |
$session->remove('google_code'); |
22 |
return $this->redirect(['import']); |
23 |
}
|
24 |
if ($response->error_description == 'Invalid code.') { |
25 |
$session->remove('google_code'); |
26 |
return $this->redirect(['import']); |
27 |
}
|
28 |
var_dump($response); |
29 |
echo Yii::t('frontend','There was an error. Please contact support.'); |
30 |
}
|
31 |
if (isset($response->access_token) || empty($response->access_token)) { |
32 |
$accesstoken = $response->access_token; |
33 |
} else { |
34 |
echo Yii::t('frontend','There was an error. No access token. Please contact support.'); |
35 |
}
|



Kailangan kong magdagdag ng pangangasiwa ng
mga pagkakamali para malaman kung bakit hindi gumagana at paganahin lahat nang
naaalinsunod.
Nahulaan mo, kapag may kondisyon na kamalian, madalas kong ididirekta pabalik sa parehong paraan ng kontroler.
Pagpoproseso ng Naibalik na Datos
Kapag lahat ay gagana, ang kasiyahan, madaling kowd ang magpoproseso sa datos. Sa kasalukuyan, kumuha kami ng 1,000 na mga tala nang limang beses, paulit-ulit na ginagawa ang mga hiling ng pagpapahina, siyempre, ay pinapapadala pabalik sa URL na ito:
1 |
$url = 'https://www.google.com/m8/feeds/contacts/default/full?max-results='.$max_results.'&start-index='.$startIndex.'&alt=json&v=3.0&oauth_token='.$accesstoken; |
2 |
$xmlresponse = $address->curl($url); |
Pagsasalin ng XML ng Google (na mahirap rin,
at may kasamang kakaibang mga baryanteng pangalan para sa mga PHP na developer,
halimbawa, mga susi tulad ng $contact['gd$email'][0]['address']
may kasamang dolyar na simbolo sa gitna.
Sa ibaba, ginagawa namin ang bawat hiling, tumatakbo gamit ang JSON na datos, at kumukuha ng mga pangalan ng mga kontak para idagdag sa talahanayan ng Adres:
1 |
// Requests the data
|
2 |
$startIndex = 1; |
3 |
$request_data = true; |
4 |
$max_results = Address::CONTACTS_PAGE_SIZE; |
5 |
$numberPages = 0; |
6 |
while ($request_data && $numberPages <5) { |
7 |
//echo 'calling with startIndex: '.$startIndex.'<br />';
|
8 |
$url = 'https://www.google.com/m8/feeds/contacts/default/full?max-results='.$max_results.'&start-index='.$startIndex.'&alt=json&v=3.0&oauth_token='.$accesstoken; |
9 |
$xmlresponse = $address->curl($url); |
10 |
$contacts = json_decode($xmlresponse,true); |
11 |
if (!isset($contacts['feed']['entry'])) { |
12 |
//var_dump ($url);
|
13 |
//var_dump ($xmlresponse);
|
14 |
exit; |
15 |
}
|
16 |
$resultsCount =count($contacts['feed']['entry']); |
17 |
//echo 'count: '.$resultsCount.'<br />';
|
18 |
//var_dump (count($contacts['feed']['entry']));
|
19 |
// process out contacts without email addresses
|
20 |
//$return = array();
|
21 |
if ($resultsCount>0) { |
22 |
foreach($contacts['feed']['entry'] as $contact) { |
23 |
if (isset($contact['gd$email'])) { |
24 |
$temp = array ( |
25 |
'firstname' => (isset($contact['gd$name']['gd$givenName']['$t'])?$contact['gd$name']['gd$givenName']['$t']:''), |
26 |
'lastname' => (isset($contact['gd$name']['gd$familyName']['$t'])?$contact['gd$name']['gd$familyName']['$t']:''), |
27 |
'fullname'=> $contact['title']['$t'], |
28 |
'email' => $contact['gd$email'][0]['address'], |
29 |
);
|
30 |
//$return[]=$temp;
|
31 |
$address->add($temp); |
32 |
} else { |
33 |
continue; |
34 |
}
|
35 |
}
|
36 |
if ($resultsCount<$max_results) { |
37 |
Yii::$app->getSession()->setFlash('success', Yii::t('backend','Your contacts have been imported.')); |
38 |
return $this->redirect(['/friend','tab'=>'address']); |
39 |
}
|
40 |
}
|
41 |
//var_dump($return);
|
42 |
$numberPages++; |
43 |
$startIndex+=$max_results; |
44 |
}
|
Pagtatrabaho gamit ang Google Kontak API ay sobrang hirap, hindi masyadong nadokumento, at nagsayang ng maraming oras para sa akin. Kahit na nakapagtrabaho na ako sa maraming APIs nang matagumpay, alam kong hindi ako eksperto pagdating dito. Dahil sa mga intinding pangseguridad, ayaw ko talagang talunin ang Google dito—sa maraming kaso nito, marahil alam nila kung bakit ginagawa nila ang mga bagay gamit ang tiyak na paraan.
Pero okey lang magsaya, diba?
Una sa lahat, lahat sa Google ay mga henyo, at napatunayan nila ulit sa pamamagitan ng pagkuha ng API.ai, isang napakatalinong serbisyo na nakakonekta sa kanilang Sign Up na pindutan sa kanilang Login na Porma. Talaga, ginawa nila:
Sigurado ako na ang pangkat ng Google sa angkop na sipag ay nakita ang pagkahenyo dito na nanatiling hindi abot sa mortal tulad ko. Malamang nasabi nila,"Wow, ang API.ai na mga programista ay mga henyo tulad ng aming AdSense at DFP na mga pangkat! Idagdag natin sila sa Alpabeto!"
Dahil baka makikipagusap ako sa anghel at mga imbestor ng VC tungkol sa Tagaplano ng Pulong sa hinaharap, gusto kong maging mapagkumbaba. Pero matatakot ako kapag ang aking tahanang pahina ang gumawa nito at isa sa inaasahan kong imbestor ang nakapansin.
Ang bagong Alpabeto (Bagong magulang na kumpanya ng Google) ay mapagpatawad.
Pagpapalawig ng Magdagdag ng mga Kalahok na Porma
Sa wakas, tingnan natin ang kowd sa likod ng pinalawig na Magdagdag ng mga Kalahok na Porma. Talaga, kumukuha ako ng mga sulatroniko mula sa talahanayan na Mga Kaibigan at pagkatapos mga sulatroniko mula sa talahanayan na Adres:
1 |
$friendsEmail=[]; |
2 |
$friendsId=[]; |
3 |
$fq = Friend::find()->where(['user_id'=>Yii::$app->user->getId()])->all(); |
4 |
// to do - add a display name field for right side of input
|
5 |
$fa = Address::find() |
6 |
->select(['id','email']) |
7 |
->where(['user_id'=>Yii::$app->user->getId()]) |
8 |
->limit(5000) |
9 |
->all(); |
10 |
foreach ($fq as $f) { |
11 |
$friendsEmail[]=$f->friend->email; // get constructed name fields |
12 |
$friendsId[]=$f->id; |
13 |
}
|
14 |
foreach ($fa as $f) { |
15 |
$friendsEmail[]=$f->email; // get constructed name fields |
16 |
$friendsId[]=$f->id; |
17 |
}
|
18 |
if (count($friendsEmail)>0) { |
19 |
?>
|
20 |
<p><strong>Choose From Your Friends</strong></p> |
21 |
<select class="combobox input-large form-control" id="participant-email" name="Participant[email]"> |
22 |
<option value="" selected="selected"><?= Yii::t('frontend','type or click to choose friends') // chg meetingjs if change string ?></option> |
23 |
<?php |
24 |
foreach ($friendsEmail as $email) { |
25 |
?>
|
26 |
<option value="<?= $email;?>"><?= $email;?></option> |
27 |
<?php
|
28 |
}
|
29 |
?>
|
30 |
<?php
|
31 |
}
|
32 |
?>
|
33 |
</select>
|
Gayunman, ang opsyon na halaga ay sulatroniko lamang sapagkat lalo siyang magiging komplikado kung magtatalaga kung aling uri ng kaibigan ito (mula sa Kaibigan o Adres na talahanayan).
Hindi ko ipinagmamalaki ang kowd at ang paraan sa itaas, pero papunta sa beta release, gumawa ako ng mga kompromiso para magawa ito.
Dahil sa 5,000 na mga Google Kontak sa aking dropdown na mga kaibigan, ang pagganap ay lalong bumagal. Marahil kailangan kong ikonek ang control sa AJAX na database na paghahanap sa lalong madaling panahon.
At nagsayang ako ng maraming oras noong nauna sa pagsubok na palawigin ang talahanayan ng mga Kaibigan para isama ang mga taong naimbitahan ko gayon din ang mga Google Kontak. Gayunman, ginawa nitong magulo ang pangangasiwa ng mga tanong tungkol sa database. Ang talahanayan ng Gumagamit na mga relasyon mula sa mga Kaibigan na talahanayan ay nagsimula ng masira para sa mga hilera ng mga Kontak kung saan sila ay walang saysay, at ito ay naging mas mahirap resolbahan. Ang pangangasiwa ng pangtanggal ng mga umiiral na mga panlabas na mga susi sa itaas at ibaba sa pamamagitan ng paglipat ay mapandaya rin.
Mga Pangwakas na Saloobin
Ang mga tampok na ito ay magagandang mga halimbawa ng mga pagsubok na umaasa sa APIs gamit ang hindi magandag mga dokumentasyon sa iyong napiling wika at paggawa ng mga kompromiso sa kowd na arkitektura para sa sandali para ilunsad ang mga tampok sa isang release na iskedyul (pinipiling huwag silang gupitin).
At may mga tiyak na isyu sa Kalakok
magdagdag ng paggawa at mga Kaibigan na pahina UX na kailangang ayusin.
Sa totoo lang, ang sakop ng Tagaplano ng Pulong ay umabot sa punto kung saan ang paggawa nito bilang isang tao ay sobrang hirap gawin. At mas makakatulong kung mas maraming mga mapagkukunan (halimbawa mga miyembro ng pangkat.)
Sa wakas, kapag hindi ka pa, iskedyul mo na ang iyong unang pulong gamit ang Tagaplano ng Pulong ngayon na! Ipaalam sa akin ang iyong naiisip sa mga puna sa ibaba. Maaari kayong makipagugnayan sa akin sa @reifman. Lagi akong bukas sa mga bagong tampok na mga ideya at mga mungkahing paksa sa mga darating na tutoryal.
Isang tutoryal sa crowdfunding ang kasalukuyang ginagawa, kaya mangyaring sundan ang aming WeFunder Tagaplano ng Pulong na pahina.
Manatiling nakatutok para sa lahat ng mga
ito at sa mga darating na mga tutoryal sa pamamagitan ng pagtingin sa Pagtatayo
ng Iyong Startup Gamit ang PHP na mga serye.