Advertisement
  1. Code
  2. Yii

Construyendo tu Startup: Control de Acceso, Relaciones de Active Records y Slugs

Scroll to top
Read Time: 17 min
This post is part of a series called Building Your Startup With PHP.
Building Your Startup With PHP: Localization With I18n
Building Your Startup With PHP: User Settings, Profile Images and Contact Details

Spanish (Español) translation by David Castrillón (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Esta es la quinta parte de la serie Construye tu Startup con PHP en Tuts +. En esta serie, te estoy guiando a través del lanzamiento de una startup desde el concepto a la realidad utilizando mi aplicación Meeting Planner como un ejemplo de la vida real. A cada paso en el camino, liberaremos el código de Meeting Planner como ejemplos de código abierto con los que se puede aprender. También veremos las cuestiones de negocios relacionados con la puesta en marcha que puedan surgir.

Todo el código para el Meeting Planner está escrito sobre el Framework de Yii2 para PHP. Si deseas más información sobre Yii2, revisa nuestra serie paralela Programación con Yii2 en Tuts +.

En este tutorial, voy a guiarte a través de más funciones del Framwork Yii que hará que nuestro código del administrador de lugares vigente sea más robusto. Vamos a implementar los controles de acceso simple de Yii para garantizar que sólo los usuarios registrados añadan lugares. Vamos a utilizar relaciones de Active Records para que solo los lugares que ha añadido el usuario aparezcan en su vista de la página de inicio del sitio. También vamos a utilizar los comportamientos de los slugs de Yii para implementar slugs de URL amigables para la visualización de estos lugares. Y vamos a hacer un poco más de limpieza y pulimento alrededor de las características del lugar.

Simplemente un recordatorio, participo en las cadenas de comentarios más abajo. Me interesa especialmente si tienes diferentes enfoques o ideas adicionales, o si quieres sugerir temas para futuros tutoriales. También recibo con gusto peticiones de características para el Meeting Planner.

Control de Acceso

El código que hemos escrito hasta el momento permite a cualquiera crear lugares incluso si no se ha registrado. Podemos utilizar funciones de control de acceso simple de Yii2 para asegurarnos de que los usuarios se registren e ingresen antes de añadir y visualizar lugares.

Yii2 también ofrece más avanzados (y complejos) Roles Basados en el Control de Acceso o (RBCA) que no implementaremos en este momento.

Si los usuarios no están conectados cuando visitan las páginas de los lugares, Yii les redirigirá a la página de inicio de sesión.

El control de acceso integrado de Yii2 soporta sólo dos roles por defecto: invitado (no conectado), representado por '?' y autenticado, representado por '@'. Si te interesa, The Code Ninja escribió un buen ejemplo para extender esto para soportar moderadores y administradores (Simpler Role Based Authorization in Yii 2.0) sin tener que recurrir al uso de RBAC.

El framework es bastante simple para poner en práctica estos controles. Nosotros sólo tenemos que añadir comportamientos a PlaceController.php que define las reglas de acceso para cada acción, por ejemplo, índice, crear, ver, etcetera. Aquí revisamos el comportamiento de acceso pero si te interesa, los filtros de verbo de Yii permiten restringir operaciones http basadas en la acción del controlador.

1
public function behaviors()
2
    {
3
        return [
4
            'verbs' => [
5
                'class' => VerbFilter::className(),
6
                'actions' => [
7
                    'delete' => ['post'],
8
                ],
9
            ],
10
            'access' => [
11
                        'class' => \yii\filters\AccessControl::className(),
12
                        'only' => ['index','create', 'create_geo','create_place_google','update','view','slug'],
13
                        'rules' => [
14
                            // allow authenticated users

15
                            [
16
                                'allow' => true,
17
                                'roles' => ['@'],
18
                            ],
19
                            // everything else is denied

20
                        ],
21
                    ],            
22
        ];
23
    }

Una vez añadidos, si haces clic en el menú de lugares (Places), serás redirigido a la página de inicio de sesión:

Meeting Planner Login PageMeeting Planner Login PageMeeting Planner Login Page

Yii también maneja la redirección a la página de índice una vez completada la sesión.

Cuando los usuarios acceden a las páginas de sitios, podemos encontrar el usuario actual con este código:

Yii:: $app-> usuario-> getId();

Por lo tanto, justo antes de que se guarden los nuevos lugares, podemos actualizar el campo de created_by al usuario actualmente conectado. Y podemos confiar en los controles de acceso para asegurarnos de que el método create tiene acceso a sólo los usuarios autenticados:

1
    public function actionCreate()
2
    {
3
        $model = new Place();       
4
        if ($model->load(Yii::$app->request->post())) {
5
          $form = Yii::$app->request->post();
6
            $model->created_by= Yii::$app->user->getId();
7
            $model->save();

Relaciones de Active Records

En el Meeting Planner, quiero seguir en primer lugar al usuario crea un lugar. Éste se almacena en el campo created_by. También queremos rastrear los sitios que los usuarios sugieren y utilizan para sus reuniones, la frecuencia con que recurren a sus lugares, y sus favoritos. Utilizamos la tabla UserPlace para esto.

Ahora que sabemos cuál usuario está registrado cuando creamos un lugar, queremos rellenar una fila relacional de la tabla de UserPlace así.

En primer lugar, tenemos que usar el generador de código de Yii, Gii (http://localhost:8888/mp/index.php/gii/model), para crear un modelo para UserPlace:

Meeting Planner Yii2 Gii Model Generator User PlaceMeeting Planner Yii2 Gii Model Generator User PlaceMeeting Planner Yii2 Gii Model Generator User Place

Entonces, cuando un lugar se agrega correctamente, queremos crear un registro en la tabla UserPlace para el usuario activo. Podemos extender Yii ActiveRecord con el método afterSave. En el modelo de lugar, agregamos:

1
public function afterSave($insert,$changedAttributes)
2
    {
3
        parent::afterSave($insert,$changedAttributes);
4
        if ($insert) {
5
          $up = new UserPlace;
6
          $up->add($this->created_by,$this->id);
7
        } 
8
    }

En el modelo de UserPlace, hemos añadido la función:

1
// add place to user place list

2
    public function add($user_id,$place_id) {
3
        // check if it exists

4
        if (!UserPlace::find()
5
            ->where( [ 'user_id' => $user_id, 'place_id' => $place_id ] )
6
            ->exists()) {
7
              // if not, add it

8
              $up = new UserPlace;
9
              $up->user_id =$user_id;
10
              $up->place_id=$place_id;
11
              $up->save();  
12
            }            
13
    }

Cuando el usuario visita la página índice de los sitios, queremos mostrarle los lugares que ha utilizado, solo las de la tabla de UserPlace para ese usuario.

Voy a guiarte a través de dos maneras diferentes de lograrlo. Como todavía estoy ganando experiencia con Yii2.x a medida que avanzo, los detalles de lo mejor eran nuevos para mí. Quiero agradecerle a Alex Makarov, un desarrollador de Yii, quien también maneja YiiFeed.com, por su ayuda. Tanto él como el fundador de Yii Qiang Xue han sido muy útiles para contestar preguntas y apoyar mis esfuerzos con estos tutoriales relacionados con Yii.

El enfoque más sencillo

La forma más fácil es unir la tabla Place con la tabla UserPlace en la propiedad de UserPlace.place_id filtrando UserPlace.user_id con el usuario actualmente autenticado.

Este es el método del controlador de índice predeterminado:

1
public function actionIndex()
2
{
3
    $searchModel = new PlaceSearch();
4
    $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
5
6
    return $this->render('index', [
7
        'searchModel' => $searchModel,
8
        'dataProvider' => $dataProvider,
9
    ]);
10
}

Vamos a crear un nuevo método de control llamado Yours:

1
    public function actionYours() 
2
    {
3
      $query = Place::find()->joinWith('userPlaces')->where(['user_id' => Yii::$app->user->getId()]);
4
      $searchModel = new PlaceSearch();
5
      
6
         $dataProvider = new ActiveDataProvider([
7
             'query' => $query,
8
             'pagination' => ['pageSize' => 10],
9
         ]);
10
11
         return $this->render('yours',[
12
            'dataProvider' => $dataProvider,
13
            'searchModel'=>$searchModel,
14
         ]);
15
    }

Aviso que joinWith('userPlaces') está utilizando la consulta relacional generada por Gii en Place.php— esto puede ser un poco confuso ya que omites el prefijo "get":

1
    /**

2
     * @return \yii\db\ActiveQuery

3
     */
4
    public function getUserPlaces()
5
    {
6
        return $this->hasMany(UserPlace::className(), ['place_id' => 'id']);
7
    }

También necesitamos modificar la clase PlaceSearch:

1
// add a required rule for created_by
2
public function rules()
3
    {
4
        return [
5
            [['created_by'], 'required'],        
6
7
// add the join within the search query
8
public function search($params)
9
    {
10
        $query = Place::find()->joinWith('user_place')->where(['user_id' => Yii::$app->user->getId()]);
11
        $dataProvider = new ActiveDataProvider([
12
            'query' => $query,
13
        ]);

Un Enfoque Alternativo

Otra forma de aplicarlo es a través de un controlador UserPlace. Después de todo, estamos viendo los "lugares del usuario". En este caso podemos hacerle una ligera modificación al método índice del controlador generado Gii:

1
public function actionIndex()
2
    {
3
        $searchModel = new UserPlaceSearch();
4
        $searchModel->user_id = Yii::$app->user->getId();
5
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
6
7
        return $this->render('index', [
8
            'searchModel' => $searchModel,
9
            'dataProvider' => $dataProvider,
10
        ]);
11
    }

En /views/user-place/index.php, necesitamos modificar las rutas de enlace generadas y el modelo de acceso a los datos, por ejemplo, /place/create_place_google/:

1
<p>
2
       <?= Html::a(Yii::t('frontend', 'Create {modelClass}', [
3
         'modelClass' => 'Place',
4
      ]), ['/place/create'], ['class' => 'btn btn-success']) ?>
5
      
6
      <?= Html::a(Yii::t('frontend','Add Current Location'), ['/place/create_geo'], ['class' => 'btn btn-success']) ?> 
7
      <?= Html::a(Yii::t('frontend','Add a Google {modelClass}',[
8
         'modelClass' => 'Place'
9
      ]), ['/place/create_place_google'], ['class' => 'btn btn-success']) ?> 
10
    </p>

En el widget de vista de Cuadrícula, utilizamos la relación UserPlace a la tabla de Place para llegar a propiedades desde el último modelo, por ejemplo $model-> place-> slug:

1
<?= GridView::widget([
2
        'dataProvider' => $dataProvider,
3
        //'filterModel' => $searchModel,

4
        'columns' => [
5
           // ['class' => 'yii\grid\SerialColumn'],

6
7
            [
8
                'attribute' => 'place_name',
9
                'format' => 'raw',
10
                'value' => function ($model) {                      
11
                            return '<div>'.$model->place->name.'</div>';
12
                    },
13
            ],
14
            [
15
                'attribute' => 'place_type',
16
                'format' => 'raw',
17
                'value' => function ($model) {                      
18
                            return '<div>'.$model->place->getPlaceType($model->place->place_type).'</div>';
19
                    },
20
            ],
21
            ['class' => 'yii\grid\ActionColumn',
22
    			      'template'=>'{view} {update} ',
23
					    'buttons'=>[
24
                'view' => function ($url, $model) {     
25
                  return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', Yii::getAlias('@web').'/place/'.$model->place->slug, ['title' => Yii::t('yii', 'View'),]);	
26
						      },
27
                 'update' => function ($url, $model) {     
28
                    return Html::a('<span class="glyphicon glyphicon-pencil"></span>', Yii::getAlias('@web').'/place/update/'.$model->place_id, ['title' => Yii::t('yii', 'Update'),]);	
29
  						    }
30
							],
31
			      ],
32
        ],
33
    ]); ?>

El enfoque de UserPlace requiere algunos cambios en los enlaces alrededor de los breadcrumbs, los widgets de enlaces de acción y los botones de comando, pero esto aún es bastante simple.

Si revisas el código de esta versión, puedes ver ambos lugares del usuario desde: http://localhost:8888/mp/place/yours y http://localhost:8888/mp/user-place. Es interesante ver cómo se puede lograr esta funcionalidad con dos enfoques diferentes en Yii.

Slugs

Una vez que se activan las pretty URLs en Yii Framework, la página de un objeto modelo suele ser algo como http://meetingplanner.com/place/692, donde 692 representa el ID del objeto para mostrar. Además de ser indescriptible para el usuario, también es menos eficaz con los motores de búsqueda. Es mejor usar los strings de las URL amigables como http://meetingplanner.com/place/caffe-seattle. Los strings se refieren a veces como un slug. Yii2 proporcionará soporte integrado para los slugs, en forma de Comportamientos Sluggables. Los comportamientos son parte del soporte de Active Record de Yii, y se pueden aplicar automáticamente a los modelos de objetos de datos.

En nuestro modelo de lugar, hemos añadido una propiedad de slug. Aquí es cómo implementamos Comportamientos Sluggables en el modelo de lugar:

1
public function behaviors()
2
    {
3
        return [
4
            [
5
                'class' => SluggableBehavior::className(),
6
                'attribute' => 'name',
7
                'immutable' => true,
8
                'ensureUnique'=>true,
9
            ],

Yii se asegurará durante la operación save() de que el campo slug se rellene con una versión amigable de la URL del campo nombre. En otras palabras, si el nombre del lugar es Oddfellows Cafe, el slug será oddfellows-café.

La propiedad inmutable asegura que el slug nunca cambia aunque sea editado el nombre descriptivo. Esto es útil para conservar los vínculos a los lugares así como las referencias del motor de búsqueda.

La propiedad ensureUnique genera un slug único añadiendo automáticamente un índice de sufijo.

El Generador de código de Yii Gii típicamente enlaza a objetos por IDs numéricos. Queremos cambiar estos enlaces para utilizar el slug. Hay dos lugares donde existe este código.

El primero es en la página de índice del sitio en la rejilla de las columnas de acción. Puedes personalizar los enlaces como este en /frontend/views/places/index.php:

1
<?= GridView::widget([
2
        'dataProvider' => $dataProvider,
3
        'filterModel' => $searchModel,
4
        'columns' => [
5
            ['class' => 'yii\grid\SerialColumn'],
6
            'name',
7
            [
8
                'attribute' => 'place_type',
9
                'format' => 'raw',
10
                'value' => function ($model) {                      
11
                            return '<div>'.$model->getPlaceType($model->place_type).'</div>';
12
                    },
13
            ],
14
            ['class' => 'yii\grid\ActionColumn',
15
    			      'template'=>'{view} {update} ',
16
					    'buttons'=>[
17
                'view' => function ($url, $model) {     
18
                  return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', 'place/'.$model->slug, ['title' => Yii::t('yii', 'View'),]);	
19
						      }
20
							],
21
			],
22
        ],
23
    ]); ?>

El otro lugar son los breadcrumbs:

Meeting Planner BreadcrumbsMeeting Planner BreadcrumbsMeeting Planner Breadcrumbs

Por ejemplo, en /frontend/views/place/update.php, necesitamos cambiar esto:

1
<?php
2
3
use yii\helpers\Html;
4
5
/* @var $this yii\web\View */
6
/* @var $model frontend\models\Place */
7
8
$this->title = Yii::t('frontend', 'Update {modelClass}: ', [
9
    'modelClass' => 'Place',
10
]) . ' ' . $model->name;
11
$this->params['breadcrumbs'][] = ['label' => Yii::t('frontend', 'Places'), 'url' => ['index']];
12
$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]];
13
$this->params['breadcrumbs'][] = Yii::t('frontend', 'Update');
14
?>

Reemplazando el código de identificación de la vista para utilizar el slug:

1
...
2
$this->params['breadcrumbs'][] = ['label' => Yii::t('frontend', 'Places'), 'url' => ['index']];
3
$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['slug', 'slug' => $model->slug]];
4
$this->params['breadcrumbs'][] = Yii::t('frontend', 'Update');
5
...

Limpieza y Pulido

A medida que vamos construyendo el Meeting Planner, habrá maratones de código para crear nuevas características y períodos necesarios para su limpieza y pulimiento. Esto será probablemente un ciclo repetitivo.

Voy a caminar a través de unos escenarios que quiero abordar en este momento. Por supuesto, continuaré limpiando las áreas necesarias en tanto vayamos desarrollando el código, tomando en cuenta los comentarios de los usuarios y mejorando el producto.

Extendiendo la Barra de Navegación

Yii2 está bien integrada con Bootstrap, por lo que sus aplicaciones se ven geniales y se ejecutan de manera  responsiva fuera de la caja. Si deseas crear una barra de navegación con menús desplegables, es útil revisar la documentación de Bootstrap y comprender en Yii2 el uso de la notación de matriz corta en PHP. La documentación del widget de barra de navegación de Yii2 no proporciona muchos ejemplos en este momento.

Me decidí a empezar a actualizar la navegación del Meeting Planner con algunos menús desplegables basados en el estado del usuario, por ejemplo invitados o autenticado.

Bootstrap Dropdown Menu in Meeting PlannerBootstrap Dropdown Menu in Meeting PlannerBootstrap Dropdown Menu in Meeting Planner

Aquí está el código que implementa lo anterior — estoy seguro de que seguiré modificándolo a medida que avanzamos:

1
NavBar::begin([
2
    'brandLabel' => Yii::t('frontend','MeetingPlanner.io'), //

3
    'brandUrl' => Yii::$app->homeUrl,
4
    'options' => [
5
        'class' => 'navbar-inverse navbar-fixed-top',
6
    ],
7
]);
8
if (Yii::$app->user->isGuest) {
9
    $menuItems[] = ['label' => Yii::t('frontend','Signup'), 'url' => ['/site/signup']];
10
    $menuItems[] = ['label' => Yii::t('frontend','Login'), 'url' => ['/site/login']];
11
} else {    
12
  $menuItems = [
13
      ['label' => Yii::t('frontend','Places'), 'url' => ['/place/yours']],              
14
  ];	
15
}
16
$menuItems[]=['label' => Yii::t('frontend','About'),
17
	'items' => [
18
		['label' => Yii::t('frontend','Learn more'), 'url' => ['/site/about']],
19
		['label' => Yii::t('frontend','Contact'), 'url' => ['/site/contact']],
20
	],
21
];    
22
if (!Yii::$app->user->isGuest) {
23
	$menuItems[] = [
24
	            'label' => 'Account',
25
	            'items' => [
26
	                 [
27
	                    'label' => Yii::t('frontend','Contact information'),
28
	                    'url' => ['/user-contact'],
29
	                ],
30
	                 [
31
	                    'label' => Yii::t('frontend','Logout').' (' . Yii::$app->user->identity->username . ')',
32
	                    'url' => ['/site/logout'],
33
	                    'linkOptions' => ['data-method' => 'post']
34
	                ],
35
	            ],
36
	        ];				
37
}            			
38
echo Nav::widget([
39
    'options' => ['class' => 'navbar-nav navbar-right'],
40
    'items' => $menuItems,
41
]);
42
NavBar::end();

Validando los Modelos Apropiadamente Antes de Guardar

Reescribí las acciones de crear en PlaceController para validar los modelos antes de intentar añadir las relaciones UserPlace. Hubo algunos casos donde podrían presentarse datos no válidos y eso rompería los intentos de añadir relaciones. Esto también asegura que los usuarios se devolverán al formulario con los mensajes de error amigables cuando las validaciones fallen.

1
public function actionCreate()
2
    {
3
        $model = new Place();       
4
        if ($model->load(Yii::$app->request->post())) {
5
    		      $form = Yii::$app->request->post();
6
            if (!is_numeric($model->place_type)) {
7
               $model->place_type=Place::TYPE_OTHER;
8
            }
9
            $model->created_by= Yii::$app->user->getId();
10
            // validate the form against model rules
11
            if ($model->validate()) {
12
                // all inputs are valid
13
                $model->save();
14
                // lookup gps location from address
15
                $model->addLocationFromAddress($model,$form['Place']['full_address']); 
16
                return $this->redirect(['view', 'id' => $model->id]);
17
            } else {
18
                // validation failed
19
                return $this->render('create', [
20
                    'model' => $model,
21
                ]);
22
            }            
23
        } else {
24
            return $this->render('create', [
25
                'model' => $model,
26
            ]);
27
        }
28
    }

Evitando Duplicados

En nuestro código de creación del lugar inicial, queremos protegernos contra duplicados. Los lugares pueden tener nombres idénticos, por ejemplo, hay muchos cafés de Starbucks (demasiados), pero queremos evitar que el lugar exacto se cree dos veces, por ejemplo, Starbucks Coffe con idéntico ID en Google PLace o idéntico nombre y dirección de la calle.

Yii ofrece validadores de modelo que se integran con ActiveForms para hacer mucho de este trabajo por nosotros. Aquí están las reglas que lo definen en el modelo de lugar:

1
/**

2
     * @inheritdoc

3
     */
4
     public function rules()
5
     {
6
         return [
7
             [['name','slug'], 'required'],
8
             [['place_type', 'status', 'created_by', 'created_at', 'updated_at'], 'integer'],
9
             [['name', 'google_place_id', 'slug', 'website', 'full_address', 'vicinity'], 'string', 'max' => 255],
10
             [['website'], 'url'],
11
             [['slug'], 'unique'],
12
             [['searchbox'], 'unique','targetAttribute' => 'google_place_id'],             
13
             [['name', 'full_address'], 'unique', 'targetAttribute' => ['name', 'full_address']],
14
         ];
15
     }

Los validadores pueden forzar a los campos requeridos y a los tipos y la longitud de los campos. También pueden validar las URLs como con el campo de la página web anterior, las direcciones de correo electrónico y mucho más. También puedes escribir validadores personalizados.

Existen varios validadores incorporados específicos de singularidad. Por ejemplo, pueden validar singularidad en campos sencillos como lo hemos hecho con el campo de slug. Pero también hay validadores de singularidad más complejos.

Cuando el usuario está agregando un lugar con Google Autocomplete, queremos reforzar la singularidad del google_place_id resultante en el campo oculto, pero queremos que el mensaje de error aparezca en el campo de searchbox. Esta definición lo logra:

1
[['searchbox'], 'unique','targetAttribute' => 'google_place_id'],             

También queremos asegurar que nombre y dirección sean únicos juntos. En otras palabras, varios lugares pueden tener el mismo nombre o la misma dirección pero no pueden ser idénticos en ambos campos. Esta definición hace esto:

1
[['name', 'full_address'], 'unique', 'targetAttribute' => ['name', 'full_address']],

Por supuesto, muchos usuarios pueden agregar el mismo lugar a su lista de UserPlaces.

Eliminando el Borrado

También quiero proteger contra el borrado de lugares. Gii, el generador automático de código de Yii, típicamente enlaza el borrado de operaciones desde la rejilla de la página de índice y la página de actualizar . Queremos eliminarlas. Y queremos restringir el acceso a la acción de eliminación del controlador.

Este es un ejemplo de la página de índice del sitio con los íconos de borrar:

Meeting Planner Place Index Page with Delete ActionMeeting Planner Place Index Page with Delete ActionMeeting Planner Place Index Page with Delete Action

cuando personalizamos los links de enlace en los slugs anteriores, eliminamos el uso predeterminado del comando delete.

Por cierto, realmente aprecio el uso de Yii de Bootstrap y los Glyphicons. Trabajan muy bien.

Aquí está la página con el botón delete:

Meeting Planner Update with Delete buttonMeeting Planner Update with Delete buttonMeeting Planner Update with Delete button

Por ahora, vamos a comentar el código para el botón de borrar en /frontend/views/place/view.php. Querríamos añadirlos de vuelta para los administradores en algún momento.

1
         <?php /* Html::a(Yii::t('frontend', 'Delete'), ['delete', 'id' => $model->id], [

2
             'class' => 'btn btn-danger',

3
             'data' => [

4
                 'confirm' => Yii::t('frontend', 'Are you sure you want to delete this item?'),

5
                 'method' => 'post',

6
             ],

7
         ]) */ ?>

Previniendo el Autocompletado del Envío de la Clave de Acceso

En cuanto estaba construyendo algo de la geolocalización con HTML5 y el código de autocompletar de Google Places, fueron apareciendo algunos errores, algunos relacionadas con JavaScript.

Por ejemplo, si pulsas la tecla Enter después de escribir en el campo de autocompletar, Google envía el formulario. Tenemos que reemplazar esto.

En nuestro create_place.js, añadimos un controlador a la tecla para que detenga el envío del formulario:

1
function setupListeners() { 
2
    // ...

3
    var place_input = document.getElementById('place-searchbox');
4
    google.maps.event.addDomListener(place_input, 'keydown', function(e) { 
5
        if (e.keyCode == 13) { 
6
            e.preventDefault();
7
        }
8
      });
9
}

Ahora cuando presionas Enter, verás el mapa en la página y podrás editar el resto del formulario antes de enviarlo.

Create a Place from Google PlacesCreate a Place from Google PlacesCreate a Place from Google Places

Revisando los Beneficios del Uso de un Framework

Mucha gente cree que PHP es una plataforma menos seria o capaz para construir cosas. Para mí, el éxito de Facebook con PHP siempre les demostrará su equivocación.

Mucha gente no ha oído de Yii Framework o desprecia el valor de los frameworks.

Brevemente en esta serie sobre una Startup, nos hemos beneficiado de un gran número de características de Yii Framwork - acelerando el desarrollo, entregando una arquitectura limpia y código de calidad:

  • Arquitectura MVC
  • Migraciones de Bases de Datos
  • Relaciones y validaciones del modelo de Active Record
  • Generación de código automatizado
  • Integración de Bootstrap y Glyphicons
  • Filtros de control de acceso
  • Comportamientos de los slugs
  • Internacionalización

Por esta razón soy un gran defensor de Yii Framework. Me ha hecho un desarrollador mucho más eficiente, capaz de ofrecer soluciones mucho más rápidamente de lo que quisiera con vainilla PHP.

¿Qué sigue?

En el siguiente tutorial de Construyendo tu Startup con PHP, vamos a construir el soporte para las configuraciones de usuarios, contacto e imagen de perfil.

Por favor siéntete libre de agregar tus preguntas y comentarios abajo, generalmente participo en las discusiones. También puedes encontrarme en Twitter @reifman o enviarme un correo directamente.

Enlaces Relacionados

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.