Yii डेवलपर साइकिल सेट

लेखक से

जब लेखक एक हब पर एक पोस्ट लिखता है, तो वह पाठकों को विषय पर सबसे पूर्ण और उपयोगी जानकारी देने की कोशिश करता है। लेकिन अगर कोई सही जवाब या समाधान नहीं है? तब यह पद केवल मन के लिए भोजन है, और मूल्य सामूहिक मन में निहित है।

मैं बहुत दूर से चला गया, मैं बहस नहीं करता, लेकिन मुझे आपकी समझ और समर्थन की उम्मीद है। डेवलपर की रोजमर्रा की समस्याओं के समाधान की बात करते हुए, विशेष रूप से वाईआईआई फ्रेमवर्क पर, मैं हमारी टीम के लिए एक प्रस्ताव पेश करता हूं। इसी समय, वे सामुदायिक विचारों में रुचि रखते हैं। अच्छा, अपने दिमाग को सुंदर पाउडर बनाना।
फॉरवर्ड।


फैशनेबल, युवा, लक्षण


ऐसी परिस्थितियां होती हैं जब मॉडल एन () पद्धति को निष्पादित करता है, और एक ही समय में सही / गलत होता है और यह ठीक है। लेकिन आमतौर पर उपयोगकर्ता यह नहीं समझते हैं कि त्रुटि क्यों हुई और इसके साथ आगे कैसे रहना है, विवरण की आवश्यकता है। यदि तर्क सरल है और आप पूर्णतावादी नहीं हैं तो यह अच्छा है - आपने नियंत्रक में थोड़ा सा व्यावसायिक तर्क दिया और विवरण के साथ त्रुटियों को प्रदर्शित किया - लेकिन हम ऐसे नहीं हैं!
और यदि विधि 20 विभिन्न त्रुटियों को ला सकती है, तो वासिका एक पाई क्यों नहीं खरीद सकती है या एक टिप्पणी पोस्ट नहीं कर सकती है।
Yii के पास मॉडल के लिए एक उत्कृष्ट मान्य () विधि है, लेकिन यह निश्चित रूप से मॉडल के डेटा के सत्यापन के लिए बंधा हुआ है और यदि आपने एक सार पद्धति बनाई है जो सीधे मॉडल से संबंधित नहीं है, तो यह उपयुक्त नहीं है।

कैसे हो सकता है?
और ऐसा है
trait CustomError { private $_errorMessages = []; /** * Use in method : return $this->setCustomErrorMessage(message); * * @param array $errorMessages * @return false */ public function setCustomErrorMessage($errorMessages) { if(!is_array($errorMessages)) $errorMessages = [$errorMessages]; $this->_errorMessages = $errorMessages; return false; } /** * @param string $errorMessage */ public function addCustomErrorMessage($errorMessage) { $this->_errorMessages[] = $errorMessage; } /** * @return array */ public function getCustomErrorMessages() { return $this->_errorMessages; } /** * @return mixed */ public function getCustomErrorMessageFirst() { return reset($this->_errorMessages); } /** * @return void */ public function clearCustomErrorMessages() { $this->_errorMessages = []; return; } } 


5 सेंट की तरह सरल कोड, लेकिन यह जीवन को बहुत आसान बनाता है। एक उदाहरण:
 class Blog extends CActiveRecord { use CustomError; //    public function checkPrivacyCreate() { // ,      ... $parent_post = $this->getPost($this->parent_post_id); if (empty($parent_post)) return $this->setCustomErrorMessage(Yii::t('blog', 'post_not_found')); ... return true; } } //    public function actionAddPost() { .... if (!$model->addPost()) Tools::jsonError($model->getCustomErrorMessages()); //   JSON   ... } 


हमें बाहर जाने के रास्ते पर क्या मिलता है? हम पर्याप्त विधियाँ प्राप्त करते हैं जो एक बूल मान लौटाते हैं, न कि विनाइग्रेटे संभावित उत्तर की तुलना में, इंट से स्ट्रिंग तक। कोई कोड दोहराव नहीं, शुद्ध DRY। हालाँकि नहीं, मुझे यकीन है कि स्मार्ट लोग एक क्लीनर विकल्प के साथ आएंगे, ठीक है, यह बहुत अच्छा होगा!

फैशनेबल सामान के साथ नीचे, बस एक कंसोल, केवल कट्टर!


स्मार्टप्रोग्रेस में, हम निरंतर एकीकरण का उपयोग करते हैं और प्रत्येक प्रतिबद्ध कई चरणों से गुजरता है, स्थानीय परीक्षण, एक देव सर्वर पर परीक्षण, उत्पादन पर परीक्षण और उपयोगकर्ताओं पर परीक्षण

इसके बारे में क्या है, और हाँ, हमारे पास पहले से ही 6 डेटाबेस हैं। प्रत्येक चरण के लिए दो, काम और परीक्षण। यह कहने के लिए कि हम प्रवास के लिए प्रार्थना कर रहे हैं, कुछ नहीं कहना है। लेकिन दुर्भाग्य की बात है कि वाईआई माइग्रेट टीम ऐसे चिड़ियाघर आधार के लिए कोई पर्याप्त समाधान नहीं देती है। हां, कुंजियों के माध्यम से आप वांछित कनेक्शन को निर्दिष्ट कर सकते हैं, लेकिन हर बार इसे लंबे, थकाऊ, आलस्य (आलस्य) के लिए करते हैं जो यह महसूस करता है कि प्रोग्रामर के बीच सहानुभूति को पुरुष एकजुटता से भी अधिक है। कला)

ओह, और मुझे खींच लिया, चलो सब प्यार करते हैं, बंग बम और ...
निर्णय
 <?php Yii::import('system.cli.commands.MigrateCommand'); class MigratecomboCommand extends MigrateCommand { public $connections = array('db', 'db_test'); //       public function actionUp($args) { if(($migrations=$this->getNewMigrations())===array()) { echo "No new migration found. Your system is up-to-date.\n"; return 0; } $total=count($migrations); $step=isset($args[0]) ? (int)$args[0] : 0; if($step>0) $migrations=array_slice($migrations,0,$step); $n=count($migrations); if($n===$total) echo "Total $n new ".($n===1 ? 'migration':'migrations')." to be applied:\n"; else echo "Total $n out of $total new ".($total===1 ? 'migration':'migrations')." to be applied:\n"; foreach($migrations as $migration) echo " $migration\n"; echo "\n"; if($this->confirm('Apply the above '.($n===1 ? 'migration':'migrations')."?")) { foreach($migrations as $migration) { foreach($this->connections as $connectionId) { // !!!   ,       $this->connectionID = $connectionId; if($this->migrateUp($migration)===false) { echo "\nMigration failed. All later migrations are canceled.\n"; return 2; } } } echo "\nMigrated up successfully.\n"; } } public function actionDown($args) { $step=isset($args[0]) ? (int)$args[0] : 1; if($step<1) { echo "Error: The step parameter must be greater than 0.\n"; return 1; } if(($migrations=$this->getMigrationHistory($step))===array()) { echo "No migration has been done before.\n"; return 0; } $migrations=array_keys($migrations); $n=count($migrations); echo "Total $n ".($n===1 ? 'migration':'migrations')." to be reverted:\n"; foreach($migrations as $migration) echo " $migration\n"; echo "\n"; if($this->confirm('Revert the above '.($n===1 ? 'migration':'migrations')."?")) { foreach($migrations as $migration) { foreach($this->connections as $connectionId) { $this->connectionID = $connectionId; if($this->migrateDown($migration)===false) { echo "\nMigration failed. All later migrations are canceled.\n"; return 2; } } } echo "\nMigrated down successfully.\n"; } } private $_db; protected function getDbConnection() { if(($this->_db=Yii::app()->getComponent($this->connectionID)) instanceof CDbConnection) return $this->_db; echo "Error: CMigrationCommand.connectionID '{$this->connectionID}' is invalid. Please make sure it refers to the ID of a CDbConnection application component.\n"; exit(1); } } 


मैं थोड़ा समझाता हूं, अप / डाउन विधि में, हम सभी कनेक्शनों के माध्यम से लूप करते हैं और बदले में प्रत्येक डेटाबेस में अपना माइग्रेशन लागू करते हैं।
एक प्राथमिक समाधान असंभव है। मेरी राय में, यहां तक ​​कि कहीं भी झाँका, मुझे पश्चाताप हुआ। लेकिन अब, एक आदेश पर्याप्त है, जो शुक्रवार शाम को भी "अमूर्त" स्थिति में किया जा सकता है।
 yiic migratecombo up(/down/create/...) 

और आपके माइग्रेशन $ कनेक्शन चर में निर्दिष्ट सभी मौजूदा डेटाबेस पर लागू होते हैं।

लेकिन बारीकियां हैं। यदि आप किसी तरह से मानक Yii विधियों का उपयोग न करके, चालाक तरीके से माइग्रेट करने का निर्णय लेते हैं, लेकिन सीधे डेटाबेस के माध्यम से, तो:
 class m140317_060002_fill_search_column extends CDbMigration { public function up() { $goals = $this->getDbConnection() //  ,  Yii::app()->db->createCommand...   $this->getDbConnection() ->createCommand("SELECT id, `name` FROM goals WHERE `moderated` != 'deleted'") ->queryAll(); 


खरगोशों पर परीक्षण, इकाई, कार्यात्मक


यह कहने के लिए कि मैं एक परीक्षण विशेषज्ञ हूं, लगभग आधे साल पहले घोषणा करने जैसा है कि क्रीमिया रूस का हिस्सा बन जाएगा।
लेकिन मैं इसे लंबे समय से कर रहा हूं और मैं चुप नहीं रह सकता, इसलिए मैं पहले से माफी मांगता हूं।

कार्यात्मक परीक्षण में, पहली बात यह आई कि साइट के लगभग सभी कार्य केवल अधिकृत उपयोगकर्ताओं के लिए उपलब्ध हैं, और जैसा कि आप जानते हैं, प्रत्येक परीक्षण के लिए वातावरण प्राचीन है।
हमने इसे तय किया
 class WebTestCase extends CWebTestCase { public $loginRequired = false; protected function setUp() { parent::setUp(); $this->setBrowser('*firefox'); $this->setBrowserUrl(TEST_BASE_URL); $this->prepareTestSession(); if($this->loginRequired) { $this->login(); } } } 


मैं लॉगिन विधि का कोड नहीं दूंगा, वहां सब कुछ विशुद्ध रूप से व्यक्तिगत है। अब टेस्ट कक्षा में loginRequired = true निर्दिष्ट करना पर्याप्त है और आपका परीक्षण एक अधिकृत उपयोगकर्ता द्वारा किया जाएगा।

मैं मेरे जैसे युवा और अनुभवहीन परीक्षकों को सलाह नहीं दे सकता, जो काल्पनिक लेकिन सबसे यथार्थवादी डेटा बनाने के लिए एक अद्भुत Faker उपकरण है। DataProvider के लिए एक अनिवार्य चीज
छोटा उदाहरण
 class MyTest extends CDbTestCase { public function newUserProvider() { //  3    $faker = \Faker\Factory::create('ru_RU'); $array = array(); for($i=0; $i<3; $i++) { $array[$i]['user']['name'] = $faker->name; $array[$i]['user']['address'] = $faker->address; $array[$i]['user']['country'] = $faker->country; } return $array; } /** * @param $user * @dataProvider newUserProvider */ public function testCreate($user) //    3        { $model = new User('signup'); $model->name = $user['name']; ... $model->save() } } 



बेशक, यह सभी चालें और बन्स नहीं हैं जिन्हें हमने स्मार्टप्रोग्रेड के विकास की लंबी अवधि में जन्म दिया था।
कई और समाधान और सुधार हैं, लेकिन मैं आपसे, प्रिय पाठकों से, अपने विचारों और सर्वोत्तम प्रथाओं को विषय पर साझा करने के लिए कहना चाहूंगा। निश्चित रूप से प्रत्येक डेवलपर के पास विभिन्न प्रकार के कार्यों के लिए सहायकों और तैयार समाधानों का एक वास्तविक चिड़ियाघर है।
मुझे उम्मीद है कि आप उन्हें मेरे साथ और पूरे हब्बर समुदाय के साथ साझा करेंगे।

Source: https://habr.com/ru/post/In217239/


All Articles