├── .gitignore ├── Back-end ├── API Hook.md ├── API_Ajax.md ├── API_actualizacion.md ├── API_referencias.md ├── APIrenderizacion.md ├── Api.md ├── Archivos.md ├── Batch.md ├── Cache.md ├── Commerce.md ├── Composer.md ├── Condiciones.md ├── Configuraciones.md ├── Consultas.md ├── Contenido_por_defecto.md ├── Debug.md ├── Drush.md ├── Email.md ├── Entidades.md ├── EntityTypeManager.md ├── Errores.md ├── Esquemas.md ├── Fechas.md ├── Formularios.md ├── InyeccionDependencias.md ├── Logs.md ├── MVC.md ├── Mensajes.md ├── Migraciones │ ├── Migrate.md │ ├── MigrateAPI.md │ ├── d7-a-d8.md │ └── importar-contenido.md ├── Multiidiomas.md ├── Nodos.md ├── PDF.md ├── Plugins │ ├── API_Plugin.md │ ├── FilterPlugin.md │ └── LanguageNegotiation.md ├── Rest.md ├── Restricciones.md ├── Rutas.md ├── Schemas.md ├── Servicios.md ├── Sesiones ├── Sqlite.md ├── Taxonomias.md ├── TempStorage.md ├── Testeo.md ├── Tokens.md ├── Usuarios.md ├── Variables.md ├── Vistas.md └── Webform.md ├── Contribucion ├── README.md ├── contribuir-modulo.md ├── corregir-parche.md ├── crear-un-parche.md ├── entorno.md ├── gitlab.md ├── merge-request.md ├── reroll.md └── utilidades.md ├── DevOps ├── IDEs │ ├── Atom.md │ └── visualstudiocode.md ├── Seguridad.md ├── ansible.md ├── composer.md ├── docker.md ├── drush.md ├── git.md ├── kubernetes.md ├── lamp.md ├── lando.md ├── linux.md ├── mysql.md ├── php.md ├── redis.md ├── sqlite.md ├── ssh.md └── xdebug.md ├── Ecosistema ├── SEO.md ├── integraciones.md └── modulos.md ├── Front-end ├── Twig.md ├── bootstrap.md ├── javascript.md ├── jinja.md ├── librerias.md ├── preprocess.md └── sub-temas.md ├── Modulos └── drupal_vuejs │ ├── drupal_vuejs.info.yml │ ├── drupal_vuejs.libraries.yml │ ├── drupal_vuejs.module │ ├── drupal_vuejs.permissions.yml │ ├── drupal_vuejs.routing.yml │ ├── js │ └── appvuejs.js │ ├── src │ └── Controller │ │ └── drupalVuejsController.php │ └── templates │ └── twigTest.html.twig ├── README.md └── Utiles ├── archivos └── drush ├── console.md ├── doxygen.md ├── jarvis ├── initHostVirtual └── restartDB ├── javascript.md ├── php.md ├── reactjs.md ├── sass.md └── utiles.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignorar configuración IDEs. 2 | .idea 3 | 4 | -------------------------------------------------------------------------------- /Back-end/API Hook.md: -------------------------------------------------------------------------------- 1 | API de Hookss 2 | ======== 3 | Los hooks son funciones a las cuales te puedes colgar para modificar comportamientos de partes de Drupal 4 | 5 | #### Preguardado de una entidad 6 | ```php 7 | /** 8 | * Implements hook_entity_presave(). 9 | */ 10 | function nombre_modulo_entity_presave(Drupal\Core\Entity\EntityInterface $entity) { 11 | switch ($entity->bundle()) { 12 | case 'nombre_sistema_entidad': 13 | $gender = $entity->get('field_gender')->value; 14 | $entity->set('field_gender2', $cgender); 15 | break; 16 | //... 17 | } 18 | } 19 | ``` 20 | 21 | #### Modificar un formulario 22 | ```php 23 | /** 24 | * Implements hook_form_alter(). 25 | */ 26 | function nombre_modulo_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) { 27 | if ($form_id == 'node_people_edit_form') { 28 | $form['field_is_single']['widget'][0]['value']['#attributes']['readonly'] = TRUE; 29 | //... 30 | return $form; 31 | } 32 | } 33 | 34 | /** 35 | * Implements hook_form_FORM_ID_alter(). 36 | */ 37 | function mombre_modulo_form_id_del_formulario_alter(array &$form, \Drupal\Core\Form\FormStateInterface $form_state) { 38 | // Prepare form for using AJAX. 39 | $form['#attached']['library'][] = 'core/drupal.dialog.ajax'; 40 | $form['caption'] = [ 41 | '#type' => 'html_tag', 42 | '#tag' => 'div', 43 | '#value' => t('Want to join our community ?'), 44 | '#weight' => -25, 45 | '#attributes' => [ 46 | 'class' => [ 47 | 'newsletter-form-caption', 48 | 'a-block-title', 49 | 'a-block-title--size--small', 50 | ], 51 | ], 52 | ]; 53 | //... 54 | } 55 | 56 | /** 57 | * Implements hook_webform_submission_form_alter(). 58 | */ 59 | function nombe_modulo_webform_submission_form_alter(array &$form, FormStateInterface $form_state, $form_id) { 60 | // Disable inline form errors summary for all webforms. 61 | $form['#disable_inline_form_errors_summary'] = TRUE; 62 | } 63 | 64 | /** 65 | * Implements hook_webform_element_alter(). 66 | */ 67 | function nombre_modulo_webform_element_alter(array &$element, FormStateInterface $form_state, array $context) { 68 | if ($element["#webform_id"] == 'job_application--job_offer_title') { 69 | if (isset($_GET["job_offer"])) { 70 | $node = Node::load($_GET["job_offer"]); 71 | if ($node instanceof NodeInterface) { 72 | $element['#markup'] = t("To apply for the « @title » offer, please complete the following form :", ['@title' => $node->getTitle()]); 73 | } 74 | } 75 | } 76 | ``` 77 | 78 | #### Modificar una view 79 | ```php 80 | /** 81 | * Implementation of hook_views_query_alter(). 82 | */ 83 | function nombre_modulo_views_query_alter(ViewExecutable $view, QueryPluginBase $query) { 84 | if ($view->id() == 'id_de_la_view') { 85 | $query->addField('node_field_data', 'nid', '', ['function' => 'groupby']); 86 | $query->addGroupBy('node_field_data.nid'); 87 | } 88 | } 89 | 90 | /** 91 | * Implements hook_views_pre_render(). 92 | */ 93 | function nombre_modulo_views_pre_render(ViewExecutable $view) { 94 | // Update title for category view. 95 | if ($view->storage->id() == 'commerce_cart_block') { 96 | $category = Term::load($id_category); 97 | $curr_langcode = \Drupal::languageManager()->getCurrentLanguage(\Drupal\Core\Language\LanguageInterface::TYPE_CONTENT)->getId(); 98 | $translated = \Drupal::service('entity.repository')->getTranslationFromContext($category, $curr_langcode); 99 | $view->setTitle($translated->getName()); 100 | } 101 | } 102 | ``` 103 | 104 | #### Modificar un bloque 105 | ```php 106 | /** 107 | * Implements hook_block_build_BASE_BLOCK_ID_alter(). 108 | */ 109 | function nombre_modulo_block_build_lang_drop_down_switcher_alter(array &$build, BlockPluginInterface $block) { 110 | $langcodes = _get_configurable_languages(); 111 | $languages_disabled = 0; 112 | 113 | foreach ($langcodes as $configurableLanguage) { 114 | $disabled = $configurableLanguage->getThirdPartySetting('disable_language', 'disable'); 115 | if (isset($disabled) && $disabled == 1) { 116 | $languages_disabled++; 117 | } 118 | } 119 | 120 | if ($languages_disabled == count($langcodes) || $languages_disabled == count($langcodes) - 1) { 121 | $build['#access'] = FALSE; 122 | } 123 | } 124 | 125 | function _get_configurable_languages() { 126 | $configurableLanguages = []; 127 | 128 | // Get all languages. 129 | $languages = \Drupal::languageManager()->getLanguages(); 130 | 131 | // The language itself doesn't own the thirdPartySetting, 132 | // So we need to use its matching ConfigEntity 133 | // Getting the ConfigurableLanguageManager. 134 | $configManager = \Drupal::entityTypeManager()->getStorage('configurable_language'); 135 | $configurableLanguages = $configManager->loadMultiple(array_keys($languages)); 136 | 137 | return $configurableLanguages; 138 | } 139 | ``` 140 | 141 | #### Modificar algo en el theme 142 | ```php 143 | /** 144 | * Implements hook_preprocess_HOOK(). 145 | */ 146 | function nombre_modulo_preprocess_block__system_branding_block(&$variables) { 147 | // @see asf_form_system_theme_settings_alter(). 148 | $svg_images = [ 149 | 'svg_logo_image' => theme_get_setting('svg_logo_image'), 150 | 'svg_logo_text' => theme_get_setting('svg_logo_text'), 151 | 152 | ]; 153 | foreach ($svg_images as $key => $svg_image) { 154 | $file = $svg_image ? File::load($svg_image[0]) : NULL; 155 | if ($file) { 156 | $variables[$key] = [ 157 | '#theme' => 'image', 158 | '#uri' => $file->getFileUri(), 159 | ]; 160 | } 161 | } 162 | } 163 | ``` 164 | 165 | #### Reparar un schema personalizado 166 | ```php 167 | /** 168 | * Implements hook_config_schema_info_alter(). 169 | */ 170 | function nombre_modulo_config_schema_info_alter(&$definitions) { 171 | // @todo: Remove once https://www.drupal.org/project/menu_multilingual/issues/2956990 is fixed. 172 | if (isset($definitions['block.settings.system_menu_block:*.third_party.menu_multilingual']['mapping']) && isset($definitions['block.settings.system_menu_block:*']['mapping'])) { 173 | $definitions['block.settings.system_menu_block:*']['mapping'] = array_merge($definitions['block.settings.system_menu_block:*']['mapping'], $definitions['block.settings.system_menu_block:*.third_party.menu_multilingual']['mapping']); 174 | } 175 | } 176 | ``` 177 | 178 | #### Modificar un tipo de contenido 179 | ```php 180 | /** 181 | * Implements hook_entity_type_build(). 182 | */ 183 | function nombre_modulo_entity_type_build(array &$entity_types) { 184 | if (isset($entity_types['node'])) { 185 | $entity_types['node']->addConstraint('UniqueIdCatalog', []); 186 | } 187 | } 188 | ``` 189 | 190 | #### Agregar una librería a una página 191 | ```php 192 | /** 193 | * Implements hook_page_attachments(). 194 | */ 195 | function nombre_modulo_page_attachments(array &$attachments) { 196 | // Gigya adds scripts in all pages so we add throbber script too. 197 | $attachments['#attached']['library'][] = 'nombre_modulo/nombre_libreria'; 198 | } 199 | ``` 200 | 201 | #### Modificar un widget 202 | ```php 203 | /** 204 | * Implements hook_field_widget_form_alter(). 205 | */ 206 | function nombre_modulo_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) { 207 | $field_definition = $context['items']->getFieldDefinition(); 208 | $paragraph_entity_reference_field_name = $field_definition->getName(); 209 | 210 | if ($paragraph_entity_reference_field_name == 'additionnal_informations') { 211 | $widget_state = WidgetBase::getWidgetState($element['#field_parents'], $paragraph_entity_reference_field_name, $form_state); 212 | $paragraph_instance = $widget_state['paragraphs'][$element['#delta']]['entity']; 213 | // Duration field should be invisible if type of contract != CDD. 214 | if ($paragraph_instance->bundle() == 'job_offer_informations') { 215 | if (isset($element['subform']['duration'])) { 216 | $dependee_field_name = 'type_of_contract'; 217 | $selector = sprintf('select[name="%s[%d][subform][%s]"]', $paragraph_entity_reference_field_name, $element['#delta'], $dependee_field_name); 218 | $element['subform']['duration']['#states'] = [ 219 | 'visible' => [ 220 | $selector => ['value' => 'cdd'], 221 | ], 222 | ]; 223 | } 224 | } 225 | } 226 | } 227 | ``` 228 | 229 | #### Modifcar un menu operations 230 | ```php 231 | /** 232 | * Implements hook_entity_operation_alter(). 233 | */ 234 | function nombre_modulo_entity_operation_alter(array &$operations, EntityInterface $entity) { 235 | // Add 'Edit all' operation to webform submissions items. 236 | if ($entity->getEntityTypeId() === "webform_submission") { 237 | /* @var $edit_operation_url Drupal\Core\Url */ 238 | $edit_operation_url = $operations['edit']['url']; 239 | if (isset($edit_operation_url)) { 240 | $url = \Drupal\Core\Url::fromRoute('entity.webform_submission.edit_form.all', $edit_operation_url->getRouteParameters()); 241 | $operation = [ 242 | 'title' => t('Edit all'), 243 | 'weight' => 0, 244 | 'url' => $url, 245 | ]; 246 | array_push($operations, $operation); 247 | } 248 | } 249 | } 250 | ``` 251 | 252 | #### Modificar o filtrar plugins por tipo y por consumidor 253 | ```php 254 | /** 255 | * Implements hook_plugin_filter_TYPE__CONSUMER_alter(). 256 | */ 257 | function nombre_modulo_plugin_filter_block__layout_builder_alter(&$definitions) { 258 | /* @var $user Drupal\user\Entity\User */ 259 | $current_user = \Drupal::currentUser(); 260 | $user = User::load($current_user->id()); 261 | // User 'contributor' can't use share this block. 262 | if ($user->hasRole('contributor')) { 263 | unset($definitions['sharethis_widget_block']); 264 | } 265 | } 266 | ``` 267 | 268 | #### Alterar las tareas de instalación - configuraciones 269 | ```php 270 | /** 271 | * Implements hook_install_tasks_alter(). 272 | */ 273 | function nombre_modulo_install_tasks_alter(&$tasks, $install_state) { 274 | // Moves the language config import task to the end of the install tasks so 275 | // that it is run after the final import of languages. 276 | $task = $tasks['sdd_install_import_language_config']; 277 | unset($tasks['sdd_install_import_language_config']); 278 | $tasks = array_merge($tasks, ['sdd_install_import_language_config' => $task]); 279 | } 280 | ``` 281 | 282 | #### Quitar una pestaña del menu de tabs de webform 283 | ```php 284 | /** 285 | * Implements hook_local_tasks_alter(). 286 | */ 287 | function nombre_modylo_local_tasks_alter(&$local_tasks) { 288 | // Unset webform submissions because we replace it by a view page with tabs for each form. 289 | unset($local_tasks['entity.webform_submission.collection']); 290 | } 291 | ``` 292 | 293 | ### Alterar los links de menús, campos de tipo link 294 | ```php 295 | /** 296 | * Implements hook_link_alter(). 297 | * 298 | * Add target="_blank" to all external links. 299 | */ 300 | function mi_modulo_link_alter(&$variables) { 301 | if ($variables['url']->isExternal()) { 302 | $webUri = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]"; 303 | /* @var $url Drupal\Core\Url */ 304 | $url = $variables['url']; 305 | $linkUri = $url->toString(); 306 | if (str_contains($linkUri, $webUri) === FALSE) { 307 | $variables['options']['attributes']['target'] = '_blank'; 308 | $variables['options']['attributes']['rel'] = 'noopener'; 309 | } 310 | } 311 | } 312 | ``` 313 | ### Alterar el modo de vista de un nodo 314 | ```php 315 | /** 316 | * Implements hook_node_view(). 317 | */ 318 | function nombre_modulo_node_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) { 319 | if ($entity->bundle() == 'landing_page' && $view_mode == "teaser") { 320 | if (empty($build['hea'][0])) { 321 | $id_empty_image = 39; 322 | $media_entity = Media::load($id_empty_image); 323 | 324 | $build['hea']['#theme'] = 'field'; 325 | $build['hea']['#title'] = 'Header image'; 326 | $build['hea']['#label_display'] = 'hidden'; 327 | $build['hea']['#view_mode'] = 'teaser'; 328 | $build['hea']['#language'] = $entity->language()->getId(); 329 | $build['hea']['#field_name'] = 'hea'; 330 | $build['hea']['#field_type'] = 'entity_reference'; 331 | $build['hea']['#field_translatable'] = FALSE; 332 | $build['hea']['#entity_type'] = 'node'; 333 | $build['hea']['#bundle'] = 'landing_page'; 334 | $build['hea']['#object'] = $entity; 335 | $build['hea']['#formatter'] = 'entity_reference_entity_view'; 336 | $build['hea']['#is_multiple'] = FALSE; 337 | $build['hea']['#third_party_settings'] = []; 338 | $build['hea'][0] = [ 339 | '#media' => $media_entity, 340 | '#view_mode' => 'card', 341 | '#cache' => [ 342 | 'tags' => [ 343 | '0' => "media:" . $id_empty_image, 344 | '1' => "media_view", 345 | ], 346 | 'contexts' => [ 347 | '0' => "route.name.is_layout_builder_ui", 348 | '1' => "user.permissions", 349 | ], 350 | 'max-age' => -1, 351 | 'keys' => [ 352 | '0' => "entity_view", 353 | '1' => "media", 354 | '2' => $id_empty_image, 355 | '3' => "card", 356 | ], 357 | 'bin' => "render", 358 | ], 359 | '#theme' => 'media', 360 | '#weight' => 0, 361 | '#pre_render' => [ 362 | '0' => [ 363 | '0' => \Drupal::entityTypeManager()->getViewBuilder('media'), 364 | '1' => 'build', 365 | ], 366 | ], 367 | ]; 368 | $build['hea']['#weight'] = 0; 369 | } 370 | } 371 | } 372 | ``` 373 | 374 | ### Aterar el form display de una entidad. 375 | ```php 376 | /** 377 | * Implements hook_entity_form_display_alte(). 378 | */ 379 | function mi_modulo_entity_form_display_alter(&$form_display, $context) { 380 | if ($context['entity_type'] == 'user' && $context['bundle'] == 'user') { 381 | $user = \Drupal::currentUser(); 382 | $user_roles = $user->getRoles(); 383 | if (array_intersect($user_roles, ['admin', 'webmaster'])) { 384 | $storage = \Drupal::service('entity_type.manager')->getStorage('entity_form_display'); 385 | $form_display = $storage->load('user.user.default'); 386 | } 387 | } 388 | } 389 | 390 | ``` 391 | ENLACES Y FUENTES 392 | ================= 393 | Lista de hooks 394 | - https://api.drupal.org/api/drupal/core!core.api.php/group/hooks/8.2.x 395 | 396 | 397 | Que son los hooks 398 | - https://drupalize.me/tutorial/what-are-hooks?p=2766 399 | - https://www.drupal.org/docs/creating-custom-modules/understanding-hooks 400 | 401 | -------------------------------------------------------------------------------- /Back-end/API_Ajax.md: -------------------------------------------------------------------------------- 1 | API de ajax 2 | ======== 3 | 4 | #### Enlaces ajax mediante la clase 'use-ajax' 5 | Trabajamos en el método que dibuja un bloque (build()). 6 | ```php 7 | public function build() { 8 | $build = []; 9 | $build[] = [ 10 | '#theme' => 'container', 11 | '#children' => [ 12 | '#markup' => '', 13 | ] 14 | ]; 15 | $url = Url::fromRoute('hello.hide_block); 16 | $url->setOption('attributes', ['class' => 'use-ajax']); 17 | $build[] = [ 18 | '#type' => 'link', 19 | '#url' => $url, 20 | '#title' => $this->t('Remove'), 21 | ] 22 | return $build; 23 | } 24 | ``` 25 | 26 | La ruta para el método que va realizar el trabajo en drupal-php 27 | ```yml 28 | hello.hide_block: 29 | path: '/hide-block' 30 | defaults: 31 | _controller: \Drupal\mi_modulo\Controller\HelloController::hideBlock 32 | requirements: 33 | _permission: 'access content' 34 | ``` 35 | 36 | El método en el Controlador 37 | ```php 38 | public function hideBlock(Request $request) { 39 | if (!$request->isXmlHttpRequest()) { 40 | throw new NotFoundHttpException(); 41 | } 42 | 43 | $response = new AjaxResponse(); 44 | $command = new RemoveCommand('.block-hello'); 45 | $response->addCommand($command); 46 | return $response; 47 | } 48 | ``` 49 | 50 | Nota: Se puede usar en Botones ajax mediante la clase 'use-ajax-submit'. 51 | 52 | #### Formularios AJAX 53 | 54 | Elemento de formulario que tiene un recargado ajax 55 | ```php 56 | $form['example_select'] = [ 57 | '#type' => 'select', 58 | '#title' => $this->t('Example select field'), 59 | '#options' => [ 60 | '1' => $this->t('One'), 61 | '2' => $this->t('Two'), 62 | '3' => $this->t('Three'), 63 | '4' => $this->t('From New York to Ger-ma-ny!'), 64 | ], 65 | '#ajax' => [ 66 | 'callback' => '::myAjaxCallback', // don't forget :: when calling a class method. 67 | //'callback' => [$this, 'myAjaxCallback'], //alternative notation 68 | 'disable-refocus' => FALSE, // Or TRUE to prevent re-focusing on the triggering element. 69 | 'event' => 'change', 70 | 'wrapper' => 'edit-output', // This element is updated with this AJAX callback. 71 | 'progress' => [ 72 | 'type' => 'throbber', 73 | 'message' => $this->t('Verifying entry...'), 74 | ], 75 | ] 76 | ]; 77 | 78 | $form['output'] = [ 79 | '#type' => 'textfield', 80 | '#size' => '60', 81 | '#disabled' => TRUE, 82 | '#value' => 'Hello, Drupal!!1', 83 | '#prefix' => '
', 84 | '#suffix' => '
', 85 | ]; 86 | 87 | if ($selectedValue = $form_state->getValue('example_select')) { 88 | // Get the text of the selected option. 89 | $selectedText = $form['example_select']['#options'][$selectedValue]; 90 | // Place the text of the selected option in our textfield. 91 | $form['output']['#value'] = $selectedText; 92 | } 93 | ``` 94 | 95 | Método que realiza el remplazo en 'plugin-configuration-wrapper' 96 | ```php 97 | public function myAjaxCallback(array &$form, FormStateInterface $form_state) { 98 | // Return the prepared textfield. 99 | return $form['output']; 100 | } 101 | 102 | ``` 103 | #### Recomendaciones importantes 104 | - En formularios, los métodos validate() y submit() se ejecutan antes de los métodos ajax y se pueden usar para actualiazar los valores de form_state. Debido a que cuando se actualiza un elemento de formulario en los métodos ajax no se actualizan sus valores form_state. 105 | - En formularios, no es buena idea generar nuevos elementos de formulario en los métodos ajax. Esto provoca errores. 106 | - En formularios, lo más usual es generar todos los elementos en el método build() para luego manipular su renderizado mediante los métodos callback ajax, form_state y el método validate() 107 | 108 | Referencias 109 | === 110 | Conceptops básicos 111 | - https://www.drupal.org/docs/drupal-apis/ajax-api/basic-concepts 112 | 113 | Documentación oficial de ajax en formularios - ejemplos 114 | - https://www.drupal.org/docs/drupal-apis/javascript-api/ajax-forms 115 | 116 | Lista de todos los métodos ajax que podemos usar desde php 117 | - https://api.drupal.org/api/drupal/core%21core.api.php/group/ajax/9.1.x 118 | 119 | 120 | Notas importantes sobre ajax a formularios mediante hook_form_alter 121 | - https://www.reddit.com/r/drupal/comments/c7bph8/adding_ajax_callback_to_form_element_using_hook/ -------------------------------------------------------------------------------- /Back-end/API_referencias.md: -------------------------------------------------------------------------------- 1 | API referencias 2 | ======== 3 | 4 | 5 | 6 | Enlaces 7 | ================= 8 | Documentación oficial 9 | https://api.drupal.org/api/drupal/8 10 | 11 | Documentación de la comunidad 12 | https://www.drupal.org/developing/api/8 13 | 14 | Clases de drupal 8 15 | https://api.drupal.org/api/drupal/classes/8 16 | 17 | Configuraciones 18 | https://www.drupal.org/developing/api/8/configuration 19 | 20 | Hoja resumida de codigo 21 | http://wizzlern.nl/sites/wizzlern.nl/files/artikel/drupal8_content_entity.pdf 22 | 23 | Watchdow drupal 8 24 | https://www.drupal.org/node/2270941 25 | 26 | Lo basico de programar en D8 27 | http://capgemini.github.io/drupal/drupal-8-in-2-steps/ 28 | 29 | Webomelette 30 | http://www.webomelette.com/ 31 | 32 | Event dispacher 33 | http://www.sitepoint.com/drupal-8-hooks-symfony-event-dispatcher/ 34 | 35 | Entity query 36 | https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Entity!Query!QueryInterface.php/function/QueryInterface%3A%3Acondition/8 37 | 38 | Entidades 39 | http://talks.shawnduncan.org/entity_talk/#/overview 40 | 41 | http://talks.shawnduncan.org/entity_talk/images/Entity.svg 42 | 43 | Recurso sobre entidades 44 | http://shawnduncan.org/entities-core-custom 45 | 46 | Programación orientada a objectos para Drupal 8 - php 47 | https://prakashdrupal.wordpress.com/2016/04/13/want-to-learn-drupal-8-custom-module/ 48 | 49 | Programación MVC sobre Drupal 8 50 | https://gist.github.com/jmolivas/d29065493a91f16f35b2 51 | 52 | Seguimiento de cambios en el Core 53 | https://www.drupal.org/list-changes/drupal 54 | 55 | Configuraciones sobre Drupal 8 56 | http://hojtsy.hu/files/ConfigSchemaCheatSheet1.5.pdf 57 | 58 | Entidades traducibles en drupal 8 59 | https://vimeo.com/166918014 60 | 61 | Definición de librerias 62 | https://ffwagency.com/blog/managing-css-and-javascript-files-drupal-8-libraries 63 | https://www.drupal.org/theme-guide/8/assets 64 | 65 | -------------------------------------------------------------------------------- /Back-end/APIrenderizacion.md: -------------------------------------------------------------------------------- 1 | API Renderización 2 | ======== 3 | 4 | 5 | 6 | 7 | 8 | ENLACES Y FUENTES 9 | ================= 10 | https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!theme.api.php/group/theme_render/ 11 | -------------------------------------------------------------------------------- /Back-end/Api.md: -------------------------------------------------------------------------------- 1 | API codigo 2 | ======== 3 | 4 | Cambiar el orden en que un módulo se implementa y sus hooks 5 | ```php 6 | // colocar en hook_install() 7 | module_set_weight('my_module', 123); 8 | ``` -------------------------------------------------------------------------------- /Back-end/Archivos.md: -------------------------------------------------------------------------------- 1 | ARCHIVOS 2 | ======== 3 | 4 | #### Escribir en un archivo 5 | ```php 6 | $file = File::create([ 7 | 'uid' => 1, 8 | 'filename' => 'nombre_archivo.txt', 9 | 'uri' => 'public://page/nombre_archivo.txt', 10 | 'status' => 1, 11 | ]); 12 | $file->save(); 13 | $dir = dirname($file->getFileUri()); 14 | if (!file_exists($dir)) { 15 | mkdir($dir, 0770, TRUE); 16 | } 17 | file_put_contents($file->getFileUri(), $content); 18 | $file->save(); 19 | ``` 20 | 21 | #### Referencias 22 | http://www.drupal8.ovh/en/tutoriels/47/create-a-file-drupal-8 23 | -------------------------------------------------------------------------------- /Back-end/Batch.md: -------------------------------------------------------------------------------- 1 | Batch 2 | === 3 | 4 | Drupal provee una API para ejecutar tareas pesadas sin que php retorne errores por capacidades de memoria. 5 | 6 | 7 | #### Ejemplo de código puesto su ejecución en batch. 8 | ```php 9 | //Verificar una lista de emails em batch. 10 | public function submitForm(array &$form, FormStateInterface $form_state) { 11 | $email_ids = $form_state->getValue('emailids'); 12 | $emails = explode("\n",$email_ids); 13 | 14 | $batch = [ 15 | 'title' => t('Sending emails...'), 16 | 'operations' => [], 17 | 'init_message' => t('Starting'), 18 | 'progress_message' => t('Processed @current out of @total.'), 19 | 'error_message' => t('An error occurred during processing'), 20 | 'finished' => '\Drupal\batch_example\DeleteNode::ExampleFinishedCallback', 21 | ]; 22 | foreach ($emails as $key => $value) { 23 | $email = trim($value); 24 | $batch['operations'][] = ['\Drupal\batch_example\EmailCheck::checkEmailExample',[$email]]; 25 | } 26 | 27 | batch_set($batch); 28 | } 29 | ``` 30 | 31 | #### Referencias 32 | Documentación API 33 | - https://api.drupal.org/api/drupal/core%21includes%21form.inc/group/batch/8.2.x 34 | 35 | Ejemplo de uso 36 | - https://opensenselabs.com/blogs/tech/how-use-batch-api-drupal-8 -------------------------------------------------------------------------------- /Back-end/Cache.md: -------------------------------------------------------------------------------- 1 | Cache 2 | === 3 | 4 | ### Operaciones sobre la cache 5 | ```php 6 | // Vaciar caches persistentes 7 | use Drupal\Core\Cache\Cache; 8 | 9 | foreach (Cache::getBins() as $service_id => $cache_backend) { 10 | $cache_backend->deleteAll(); 11 | } 12 | ``` 13 | 14 | ENLACES Y FUENTES 15 | ================= 16 | https://api.drupal.org/api/drupal/core%21core.api.php/group/cache/8.2.x 17 | 18 | - Errores y casos comunes 19 | https://www.lullabot.com/articles/common-max-age-pitfalls-with-drupal-cache -------------------------------------------------------------------------------- /Back-end/Commerce.md: -------------------------------------------------------------------------------- 1 | Commerce el ecosistema para hacer comercio electrónico de Drupal 2 | ======== 3 | 4 | #### Manipular entidades programaticamente 5 | ```php 6 | // Obener productos 7 | $query = \Drupal::entityQuery('commerce_product') 8 | ->condition('status', 1); 9 | $and = $query->andConditionGroup(); 10 | $and->condition('field_categoy', $category); 11 | $query->condition($and); 12 | if ($subcategory != 0) { 13 | $and = $query->andConditionGroup(); 14 | $and->condition('field_categoy', $subcategory); 15 | $query->condition($and); 16 | } 17 | $product_ids = $query->execute(); 18 | $products = []; 19 | 20 | foreach ($product_ids as $product_id) { 21 | $products[] = [ 22 | 'id' => $product_id, 23 | ]; 24 | } 25 | 26 | 27 | // Obtener producto por parametro 28 | $parameter = \Drupal::routeMatch()->getParameter('commerce_product'); 29 | $product = \Drupal\commerce_product\Entity\Product::load((int)$parameter->id()); 30 | 31 | // Cargar product variations 32 | $entity_manager = \Drupal::entityManager(); 33 | $product_variation = $entity_manager->getStorage('commerce_product_variation')->load((int)$product->getVariationIds()[0]); 34 | $price_number = $product_variation->get('price')->getValue()[0]['number']; 35 | $price_currency = $product_variation->get('price')->getValue()[0]['currency_code']; 36 | ``` 37 | 38 | 39 | #### Módulos recomendads 40 | Commerce Reporting 41 | 42 | Nos da reportes gráficos y en tablas de clientes, productos, pagos por periodos de tiempo. 43 | - https://www.drupal.org/project/commerce_reports 44 | 45 | Commerce Stock 46 | 47 | Permite gestionar el stock para las Tiendas. 48 | - https://www.drupal.org/project/commerce_stock 49 | 50 | ### Diagrama relación de entidades 51 | - https://docs.drupalcommerce.org/commerce2/developer-guide/core/relationships 52 | 53 | 54 | ENLACES Y FUENTES 55 | ================= 56 | Documentación API para drupal 8 (commerce 2) 57 | - https://docs.drupalcommerce.org/commerce2/getting-started 58 | 59 | Recetas de código 60 | - https://docs.drupalcommerce.org/commerce2/developer-guide/products/product-management/code-recipes 61 | 62 | Código para agregar al carrito 63 | - https://www.valuebound.com/resources/blog/how-to-add-a-product-programmatically-to-drupal-commerce-cart -------------------------------------------------------------------------------- /Back-end/Composer.md: -------------------------------------------------------------------------------- 1 | Composer 2 | ======== 3 | #### Manejar varias version 4 | ```bash 5 | # Cambiar a la version 1 6 | composer self-update --1 7 | 8 | # Cambiar a la version 2 9 | composer self-update --2 10 | 11 | # Volver a la version anterior 12 | composer self-update --rollback 13 | ``` 14 | 15 | #### Crear un nuevo proyecto 16 | ```bash 17 | # Version específica. 18 | composer create-project drupal/recommended-project:8.9.8 my_site_name_dir 19 | 20 | # Version recomendada 21 | composer create-project drupal/recommended-project my_site_name_dir 22 | ``` 23 | 24 | #### Resolver dependencias de librerias js de módulos contribuidos 25 | 26 | Resolver dependencias haciendo un merge. Útil para proyectos en github 27 | ```bash 28 | composer require wikimedia/composer-merge-plugin 29 | ``` 30 | 31 | Editar composer.json agregar en la sección "extra" 32 | ```json 33 | "merge-plugin": { 34 | "include": [ 35 | "docroot/modules/contrib/webform/composer.libraries.json" 36 | ] 37 | }, 38 | ``` 39 | 40 | From now on, every time the "composer.json" file is updated, it will also read the content of "composer.libraries.json" file located at web/modules/contrib/webform/ and update accordingly. 41 | 42 | In order for the "composer.json" file to install all the libraries mentioned inside the "composer.libraries.json", from the Git bash composer update --lock 43 | 44 | 45 | #### Requerir un nuevo componente 46 | 47 | ```bash 48 | # Ver todas las versiones de un proyecto. 49 | composer show drupal/account_field_split --all 50 | 51 | # Versión en producción 52 | composer require drupal/adminimal_theme:^1.3 53 | 54 | # Alfa 55 | composer require drupal/domain_entity:^1.0@alpha 56 | 57 | # Beta 58 | composer require drupal/better_normalizers:^1@beta 59 | 60 | # Rama en desarrollo 61 | composer require drupal/flexslider:^dev 62 | composer require drupal/http_status_code:1.x-dev 63 | # Fork 64 | composer require drupal/entity_reference_facet_link:dev-3254358-can-not-update 65 | 66 | # Requerir un proyecto para un determinado ambiente (dev) 67 | composer require --dev phpunit/phpunit 68 | ``` 69 | 70 | #### Actualizar un módulo, tema 71 | 72 | ```bash 73 | # Listar actualizaciones posibles. 74 | composer outdated "drupal/*" 75 | 76 | # Listar actualizaciones de seguridad. 77 | drush pm:security 78 | 79 | # Instalar actualizaciones 80 | composer update drupal/nombre_modulo --with-dependencies 81 | drush updatedb 82 | drush cache:rebuild 83 | drush config:export --diff 84 | 85 | # Actualiza módulo para apartado require-dev 86 | composer require --dev drupal/upgrade_status:^3.17 --with-all-dependencies 87 | 88 | # Actualizaciones con revisión previa de compatibilidad 89 | composer require 'drupal/core-recommended:^10' 'drupal/core-composer-scaffold:^10' 'drupal/core-project-message:^10' --no-update 90 | composer update --dry-run 91 | composer update 92 | composer install 93 | ``` 94 | 95 | #### Remover un componente 96 | 97 | ``` 98 | # composer remove drupal/config_filter 99 | ``` 100 | 101 | #### Pulgins 102 | https://www.drupaleasy.com/blogs/ultimike/2020/06/composer-plugins-drupal-developers?utm_source=drupal-newsletter&utm_medium=email&utm_campaign=drupal-newsletter-20200625 103 | 104 | 105 | #### Problemas comunes 106 | ```bash 107 | # La memoria especificada para ejecución de php no es suficiente 108 | php -d memory_limit=-1 composer require 109 | ``` 110 | 111 | ```bash 112 | # [ErrorException] 113 | # Undefined index: extra 114 | composer update zaporylie/composer-drupal-optimizations --no-plugins && composer update --lock 115 | ``` 116 | 117 | #### Actualizar el core 118 | ```bash 119 | composer update drupal/core-recommended --with-dependencies 120 | composer update drupal/core --with-dependencies 121 | 122 | // Actualizar manualmente composer.json los valores roecommended luego 123 | composer update drupal/core "drupal/core-*" --with-all-dependencies 124 | 125 | ``` 126 | 127 | - https://www.drupal.org/docs/updating-drupal/updating-drupal-core-via-composer#update-all-steps 128 | - https://www.drupal.org/docs/updating-drupal/update-drupal-core-via-composer 129 | - https://www.drupal.org/docs/upgrading-drupal/upgrading-from-drupal-8-to-drupal-9-or-higher 130 | 131 | #### Usar composer en un proyecto que fue instalado sin composer 132 | - Si el proyecto es Drupal 8.8.0 este ya tiene composer y sólo es necesario entonces instalar todos los módulos en la versión actual. 133 | 134 | ### Actualizar composer 135 | ```bash 136 | # Degrada a composer 1. 137 | sudo composer self-update --1 138 | 139 | # Actualizar a composer 2 140 | sudo composer self-update --2 141 | ``` 142 | 143 | #### Instalar librería externa 144 | En `composer.json` agregar este código dentro de la sección `repositories`: 145 | ```json 146 | { 147 | "type": "package", 148 | "package": { 149 | "name": "library-magnific/magnific-popup", 150 | "version": "1.1.0", 151 | "type": "drupal-library", 152 | "source": { 153 | "url": "https://github.com/dimsemenov/Magnific-Popup", 154 | "type": "git", 155 | "reference": "1.1.0" 156 | } 157 | } 158 | }, 159 | ``` 160 | Ejecutar `composer require --prefer-dist library-magnific/magnific-popup:1.1.*` para instalar. 161 | 162 | ### Resolver problemas de compatibilidad. 163 | Agregar el MR de gitlab, 164 | ```yml 165 | "repositories": [ 166 | { 167 | "type": "composer", 168 | "url": "https://packages.drupal.org/8", 169 | "exclude": [ 170 | "drupal/rng" 171 | ] 172 | }, 173 | { 174 | "type": "git", 175 | "url": "https://git.drupalcode.org/issue/rng-3218000.git" 176 | } 177 | ], 178 | ``` 179 | Ejecutar comando: 180 | ```bash 181 | $ composer require drupal/rng:dev-8.x-1.x 182 | ``` 183 | 184 | ENLACES Y FUENTES 185 | ================= 186 | Resolver dependencias de webform 187 | - https://www.drupal.org/docs/8/modules/webform/webform-frequently-asked-questions/how-to-use-composer-to-install-libraries 188 | 189 | Todas las opciones de actualización 190 | - https://www.drupal.org/docs/updating-drupal 191 | 192 | Actualizando módulos y temas 193 | - https://www.drupal.org/docs/updating-drupal/updating-modules-and-themes-using-composer 194 | 195 | Para actualizar composer from 1 to 2 196 | - https://www.drupal.org/docs/develop/using-composer/preparing-your-site-for-composer-2 197 | 198 | Para actualizar un propyecto que fue instalado sin composer 199 | - https://www.drupal.org/docs/installing-drupal/add-composer-to-an-existing-site 200 | 201 | Guía completa drupal-composer 202 | - https://www.drupal.org/docs/develop/using-composer/using-composer-to-install-drupal-and-manage-dependencies 203 | 204 | Resolver problemas de compatibilidad 205 | - https://www.drupal.org/docs/develop/git/using-git-to-contribute-to-drupal/creating-issue-forks-and-merge-requests#s-useissue-forks-to-makecompatibility-fixes-work-with-composer 206 | 207 | Composer update para d9 drupal/core-recommended 208 | - https://www.drupal.org/docs/updating-drupal/updating-drupal-core-via-composer -------------------------------------------------------------------------------- /Back-end/Condiciones.md: -------------------------------------------------------------------------------- 1 | Condiciones 2 | ======== 3 | Las condiciones se puede agregar en cualquier campo que lo requiera (panels, commerce cart, descuentos, bloques condicionales etc) 4 | 5 | #### Ejemplo condición extendida de base (usable desde commerce conditions) 6 | ```php 7 | namespace Drupal\extended_commerce\Plugin\Commerce\Condition; 8 | 9 | use Drupal\commerce\Plugin\Commerce\Condition\ConditionBase; 10 | use Drupal\Core\Entity\EntityInterface; 11 | use Drupal\Core\Form\FormStateInterface; 12 | 13 | /** 14 | * Provides a basic condition for orders. 15 | * 16 | * @CommerceCondition( 17 | * id = "custom_module_order_specific_customer", 18 | * label = @Translation("Specific customer"), 19 | * category = @Translation("Customer"), 20 | * entity_type = "commerce_order", 21 | * ) 22 | */ 23 | class OrderSpecificCustomer extends ConditionBase { 24 | 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | public function defaultConfiguration() { 29 | return [ 30 | 'customer' => NULL, 31 | ] + parent::defaultConfiguration(); 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public function buildConfigurationForm(array $form, FormStateInterface $form_state) { 38 | $form = parent::buildConfigurationForm($form, $form_state); 39 | 40 | $form['customer'] = [ 41 | '#type' => 'textfield', 42 | '#default_value' => $this->configuration['customer'], 43 | '#required' => TRUE, 44 | ]; 45 | 46 | return $form; 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { 53 | parent::submitConfigurationForm($form, $form_state); 54 | 55 | $values = $form_state->getValue($form['#parents']); 56 | $this->configuration['customer'] = $values['customer']; 57 | } 58 | 59 | /** 60 | * {@inheritdoc} 61 | */ 62 | public function evaluate(EntityInterface $entity) { 63 | $this->assertEntity($entity); 64 | /** @var \Drupal\commerce_order\Entity\OrderInterface $order */ 65 | if ($customer_id = $order->getCustomerId()) { 66 | // Condition is TRUE only for customer with ID #2. 67 | return ($customer_id == $this->configuration['customer']); 68 | } 69 | 70 | return FALSE; 71 | } 72 | 73 | } 74 | ``` 75 | #### Ejemplo condición extendida de plugin base (usable desde panels, etc) 76 | ```php 77 | currentRouteMatch = $current_route_match; 122 | } 123 | 124 | /** 125 | * {@inheritdoc} 126 | */ 127 | public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { 128 | return new static( 129 | $configuration, 130 | $plugin_id, 131 | $plugin_definition, 132 | $container->get('current_route_match') 133 | ); 134 | } 135 | 136 | /** 137 | * {@inheritdoc} 138 | */ 139 | public function buildConfigurationForm(array $form, FormStateInterface $form_state) { 140 | $form['status_text'] = [ 141 | '#type' => 'markup', 142 | '#markup' => $this->t('Node with custom_field status field is being viewed'), 143 | ]; 144 | 145 | return parent::buildConfigurationForm($form, $form_state); 146 | } 147 | 148 | /** 149 | * {@inheritdoc} 150 | */ 151 | public function summary() { 152 | return ($this->isNegated()) 153 | ? $this->t('Node with custom_field status field is not being viewed') 154 | : $this->t('Node with custom_field status field is being viewed'); 155 | } 156 | 157 | /** 158 | * {@inheritdoc} 159 | */ 160 | public function evaluate() { 161 | $node = $this->currentRouteMatch->getParameter('node'); 162 | return ($node && $node->hasField('custom_field') && $node->custom_field->value); 163 | } 164 | 165 | } 166 | ``` 167 | 168 | 169 | 170 | ENLACES Y FUENTES 171 | ================= 172 | Colección de condition plugins 173 | - https://www.drupal.org/project/condition_plugins 174 | 175 | -------------------------------------------------------------------------------- /Back-end/Configuraciones.md: -------------------------------------------------------------------------------- 1 | Configuraciones 2 | === 3 | 4 | #### Operaciones con el API 5 | ```php 6 | //Cron 7 | \Drupal::config('system.cron')->get('threshold.autorun') 8 | \Drupal::state()->get('system.cron_last') 9 | 10 | //Email 11 | \Drupal::config('user.mail')->get('register_admin_created.subject'); 12 | \Drupal::config('user.mail')->get('register_admin_created.body'); 13 | 14 | //Escribiendo configuraciones 15 | $config = \Drupal::service('config.factory')->getEditable('system.performance'); 16 | $config->set('cache.page.enabled', 1); // Set a scalar value. 17 | $page_cache_data = array('enabled' => 1, 'max_age' => 5); // Set an array of values. 18 | $config->set('cache.page', $page_cache_data); 19 | $config->save(); 20 | 21 | //Servicios 22 | $resource_id = 'product_resource'; 23 | $resources = \Drupal::config('rest.settings')->get('resources') ?: array(); 24 | $resources[$resource_id] = array(); // reset de resource configuration 25 | $method = "GET"; 26 | 27 | $resources[$resource_id][$method] = array(); 28 | $resources[$resource_id][$method]['supported_formats'] = array("json"); 29 | $resources[$resource_id][$method]['supported_auth'] = array("cookie"); 30 | 31 | \Drupal::configFactory()->getEditable('rest.settings') 32 | ->set('resources', $resources) 33 | ->save(); 34 | 35 | //Sistema 36 | \Drupal::configFactory()->getEditable('system.site') 37 | ->set('page.404', 'not-found') 38 | ->save(); 39 | 40 | ``` 41 | 42 | Config Split 43 | ```bash 44 | # Drush 8 o anterior: 45 | drush config-split-import config_dev 46 | 47 | # Drush 9 o posterior: 48 | drush config-split:import config_dev 49 | 50 | ## Verificar la configuraciones sobreescritas. 51 | 52 | # Drush 8 o anterior: 53 | drush config-export 54 | 55 | # Drush 9 o posterior: 56 | drush config:export 57 | 58 | # Editar una configuración activa 59 | drush config-edit nombre.configuración 60 | ``` 61 | 62 | ### Referencias 63 | Config split 64 | - https://www.drupal.org/docs/contributed-modules/configuration-split/creating-a-simple-split-configuration-dev-modules-only 65 | - https://www.specbee.com/blogs/how-to-split-configurations-across-different-sites-on-drupal-9?utm_source=drupal-newsletter&utm_medium=email&utm_campaign=drupal-newsletter-20210708 66 | 67 | Buena guía de módulos, comandos y algo de código. 68 | - https://www.daggerhartlab.com/drupal-8-configuration-management-with-config-split/ -------------------------------------------------------------------------------- /Back-end/Consultas.md: -------------------------------------------------------------------------------- 1 | Consultas 2 | === 3 | 4 | #### Consultas mediante sql 5 | ```php 6 | $db = \Drupal::database(); 7 | 8 | //Método 1 9 | $query = $db->select('k_product', 'p'); 10 | $query->fields('p', ['idpr', 'name', 'type']); 11 | $data = $query->execute()->fetchAllAssoc('idpr', 'name', 'type'); 12 | 13 | //Método 2 14 | // Dado: 15 | $sql = "SELECT idpr, name, code, detail FROM k_product"; 16 | // Obtener un array asociativo simple 17 | $data = $db->query($sql)->fetchAll(\PDO::FETCH_ASSOC); 18 | // Obtener un array asociativo. Con 'idpr' como identificador de cada subarray asociativo 19 | $data = $db->query($sql)->fetchAllAssoc('idpr', 'FETCH_ASSOC'); 20 | 21 | // Obtener sólo un dato puntual 22 | $sql = "SELECT idpr FROM k_product WHERE name = :name;"; 23 | $id_product = $db->query($sql, array(':name' => 'Lapiz'))->fetchField(0); 24 | 25 | DEPRECADOS. 26 | //múltiples filas 27 | $result = db_query('SELECT id, qualifier, email, board, popup 28 | FROM {k_message} 29 | WHERE rule = :rid', 30 | array(':rid' => $idRule) 31 | ); 32 | 33 | foreach ($result as $record) { 34 | $idMessage = $record->id; 35 | $qualifier = $record->qualifier; 36 | $emailMsg = $record->email; 37 | $boardMsg = $record->board; 38 | $popupMsg = $record->popup; 39 | } 40 | 41 | //optener valor de un sólo campo 42 | $addFactor = db_query('SELECT value FROM k_factor WHERE id = :id;', array(':id' => $id))->fetchField(); 43 | ``` 44 | -------------------------------------------------------------------------------- /Back-end/Contenido_por_defecto.md: -------------------------------------------------------------------------------- 1 | Contenido por defecto 2 | ======== 3 | 4 | #### 1. Obtener el módulo default_content y better normalizers 5 | ```bash 6 | $ composer require drupal/default_content:^1@alpha 7 | $ composer require drupal/better_normalizers:^1@beta 8 | ``` 9 | NOTA: El módulo "Better normalizers" se utiliza para generar archivos "file" (ejemplo un svg) 10 | 11 | #### 2. Activar los módulos 12 | ```bash 13 | $ drush en -y default_content better_normalizers 14 | ``` 15 | 16 | #### 3. Crear un módulo para contener los contenidos 17 | ```bash 18 | $ drush generate module-standard 19 | // Crear carpeta que va contener el contenido generado 20 | $ mkdir docroot/modules/custom//content 21 | ``` 22 | 23 | #### 4. Crear los contenidos haciendo site building 24 | ``` 25 | ... 26 | ``` 27 | 28 | #### 5. Generar los contenidos para ser reutilizados usando comandos. 29 | ```bash 30 | $ drush dcer node 31 | $ drush dcer taxonomy_term 32 | $ drush dcer file 33 | $ drush dcer media 34 | $ drush dcer menu_link_content 35 | $ drush dcer block_content 36 | $ drush dcer user 37 | $ drush dcer commerce_store 38 | $ drush dcer commerce_product 39 | ``` 40 | 41 | Comandos para genear contenidos customizando la ruta donde colocarlo. 42 | ```bash 43 | $ drush dcer node --folder=modules/custom//content 44 | ``` 45 | 46 | #### 5. Desactivar los módulos para generar contenidos 47 | // Desactivar módulos default_content, better_normalizers 48 | ```bash 49 | $ drush pmu default_content better_normalizers 50 | ``` 51 | 52 | ### Utilizando migrate_generator 53 | https://www.drupal.org/project/migrate_generator 54 | (por revizar) 55 | 56 | ENLACES Y FUENTES 57 | ================= 58 | Documentación oficial 59 | - https://www.drupal.org/docs/8/modules/default-content-for-d8/overview -------------------------------------------------------------------------------- /Back-end/Debug.md: -------------------------------------------------------------------------------- 1 | Depurar el código 2 | ======== 3 | 4 | #### Xdebug en local 5 | Permite ver las variables y su contenido de manera eficiente y en tu editor de código favorito 6 | 7 | 1. Instalar 8 | ``` 9 | $ sudo apt-get install php-xdebug 10 | 11 | // Configurar en php.ini 12 | html_errors = On 13 | 14 | // Configuraciones en php.ini opcionales 15 | display_errors = On 16 | display_startup_errors = On 17 | error_reporting = E_ALL 18 | ``` 19 | 20 | 2. Configurar xdebug 21 | en /etc/php/[version_php]/mods-available/xdebug.ini 22 | ``` 23 | zend_extension=/usr/lib/php/20190902/xdebug.so 24 | xdebug.remote_autostart = 1 25 | xdebug.remote_enable = 1 26 | xdebug.remote_handler = dbgp 27 | xdebug.remote_host = 127.0.0.1 28 | xdebug.remote_log = /tmp/xdebug_remote.log 29 | xdebug.remote_mode = req 30 | xdebug.remote_port = 9000 31 | ``` 32 | 3. Reiniciar servicios 33 | ``` 34 | $ service apache2 restart 35 | ``` 36 | 37 | 4. Instalar plugin para el navegador web 38 | ``` 39 | Plugin chrome 40 | https://chrome.google.com/webstore/detail/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc/related 41 | ``` 42 | 43 | 4. Configurar phpStorm 44 | ``` 45 | - Verificar si tenemos el proyecto con Xdebug 46 | Confurations > Languages & Framework > PHP > Debug > Validate 47 | 48 | - Configurar la conexión en "Edit configurations" (menú superior lado izquierdo de play) 49 | Crear desde Templates un "PHP Web Page" 50 | Colocar 51 | Start ULR: / (u otro url del proyecto) 52 | Browser: Chrome (u otro) 53 | 54 | En "server" dar click en "..." 55 | Host:mi_proyecto_local.com 56 | Port: 80 57 | Debugger: Xdebug 58 | Check "Use path mappings..." 59 | En "Absolute path on the server" colocar la ruta al index del proyecto. Ej: /var/www/html/mi_proyecto_local/docroot 60 | 61 | - Empezar a escuchar conexiones php debug 62 | Dar click en el icono telefono "Start listening" 63 | 64 | - Empezar a debuguear 65 | Navegar en el proyecto 66 | ``` 67 | 68 | #### Xdebug en docker 69 | 70 | 71 | ENLACES Y FUENTES 72 | ================= 73 | https://lucidar.me/en/aws-cloud9/how-to-install-and-configure-xdebug-on-ubuntu/ 74 | 75 | https://dev.to/thamaraiselvam/configure-xdebug-php-7-nginx-any-linux-distribution-3ic0 76 | 77 | https://gist.github.com/RazaChohan/51bffc660d52eae8a75dd0f9503740bf 78 | 79 | https://blog.liip.ch/archive/2016/06/20/lets-debug-drupal-8.html 80 | -------------------------------------------------------------------------------- /Back-end/Drush.md: -------------------------------------------------------------------------------- 1 | Drush 2 | === 3 | 4 | Se pueden programar nuevos comandos para drush. 5 | 6 | 7 | #### Ejemplo comando 8 | ```php 9 | namespace Drupal\mi_modulo\Commands; 10 | 11 | use Drupal\mi_modulo\LocalsHandlerInterface; 12 | use Drush\Commands\DrushCommands; 13 | 14 | /** 15 | * Drush commands concerning centers. 16 | */ 17 | class MiNuevoCommando extends DrushCommands { 18 | 19 | /** 20 | * The locals service handler. 21 | * 22 | * @var \Drupal\mi_modulo\LocalsHandlerInterface 23 | */ 24 | protected $localsHandler; 25 | 26 | /** 27 | * Commands constructor. 28 | * 29 | * @param \Drupal\mi_modulo\LocalsHandlerInterface $locals_handler 30 | * The locals handler service. 31 | */ 32 | public function __construct(LocalsHandlerInterface $locals_handler) { 33 | parent::__construct(); 34 | $this->localsHandler = $locals_handler; 35 | } 36 | 37 | /** 38 | * Import Local nodes from Loclas service information. 39 | * 40 | * @param string $local_id 41 | * Local ID. 42 | * 43 | * @command mi_modulo-locals:import-locals 44 | * 45 | * @usage drush mi_modulo-locas:import-locals 46 | * Creates nodes for centers of default area 1. 47 | */ 48 | public function importLocals($local_id = '1') { 49 | $locals = $this->centersHandler->initializeCenters([$local_id]); 50 | if (isset($locals['local_' . $local_id])) { 51 | $this->output()->writeln( 52 | 'An amount of ' . count($locals['area_' . $local_id]) . ' locals where successfully imported.' 53 | ); 54 | } 55 | else { 56 | $this->output()->writeln('The entered Local ID "' . $local_id . '" did not match any result.'); 57 | } 58 | } 59 | 60 | } 61 | 62 | ``` 63 | 64 | #### Referencias 65 | Documentación API 66 | - https://api.drupal.org/api/drupal/core%21includes%21form.inc/group/batch/8.2.x 67 | 68 | Ejemplo de uso 69 | - https://opensenselabs.com/blogs/tech/how-use-batch-api-drupal-8 -------------------------------------------------------------------------------- /Back-end/Email.md: -------------------------------------------------------------------------------- 1 | EMAIL 2 | ======== 3 | #### Envío de email por código 4 | ```php 5 | // En caso de tener que enviar un archivo adjunto. 6 | $file = file_save_data($output, $destination, FileSystemInterface::EXISTS_REPLACE); 7 | $file->setTemporary(); 8 | $file->save(); 9 | $this->fileName = $file->label(); 10 | $attachment = [ 11 | 'filecontent' => file_get_contents($destination), 12 | 'filename' => $file->label(), 13 | 'filemime' => 'application/pdf' 14 | ]; 15 | 16 | // Obtener las configuraciones para enviar. 17 | $tempstore = \Drupal::service('tempstore.private'); 18 | $store = $tempstore->get('views_bulk_operations_' . $this->view->id() . '_' . $this->view->current_display); 19 | $subject = $store->get('subject'); 20 | $email = $store->get('email'); 21 | $body = $store->get('body'); 22 | 23 | // Enviar el email. 24 | $mail_manager = \Drupal::service('plugin.manager.mail'); 25 | $lang_code = \Drupal::languageManager()->getCurrentLanguage()->getId(); 26 | $params = [ 27 | 'subject' => $subject, 28 | 'to' => $email, 29 | 'body' => $body, 30 | ]; 31 | $params['attachments'][] = $attachment; 32 | $mail_manager->mail('nombre_modulo', 'clave_envio', $params['to'], $lang_code, $params, NULL, TRUE); 33 | 34 | // @Por verificar pero algunas veces se necesita este hook más 35 | /** 36 | * Implements hook_mail(). 37 | */ 38 | function mi_modulo_mail($key, &$message, $params) { 39 | $options = [ 40 | 'langcode' => 'es', 41 | ]; 42 | 43 | switch ($key) { 44 | case 'clave_envio': 45 | $message['from'] = \Drupal::config('system.site')->get('mail'); 46 | $message['to'] = $params['to']; 47 | $message['subject'] = $params['subject']; 48 | $message['body'][] = $params['body']; 49 | break; 50 | } 51 | } 52 | ``` 53 | 54 | #### SwiftMailer 55 | ```bash 56 | # Estando en la rais del proyecto drupal 57 | composer require drupal/swiftmailer 58 | 59 | # Instalar el módulo SwiftMailer 60 | drush en swiftmailer 61 | 62 | # Configurar en la ruta: /admin/config/swiftmailer/transport 63 | # Transport types puede estar en el de tu preferencia 64 | # En la pestaña mensajes elige HTML y desmarca "Respect provided e-mail format." 65 | 66 | # Instalar el módulo MailSystem 67 | drush en mailsystem 68 | # Configurar en la ruta admin/config/system/mailsystem 69 | # Formater y Sender deben estar en SwiftMailer, Theme puede estar en el Tema por defecto o en SwiftMailer 70 | 71 | # Customizar el template html 72 | # En la ruta /modules/swiftmailer/templates/swiftmailer.html.twig se encuentra el template base. 73 | ``` 74 | 75 | #### Bug.. 76 | Si aunque este todo bien configurado el sitio no logra mandar email html.. este hook lo resuelve 77 | ```php 78 | use Drupal\Core\Render\Markup; 79 | 80 | /** 81 | * Implements hook_mail_alter() 82 | * @return mixed 83 | */ 84 | function nombreModulo_mail_alter(&$message) { 85 | $message['body'][0] = Markup::create($message['body'][0]); 86 | } 87 | ``` 88 | Tambien funciona 89 | ``` 90 | check_markup( 91 | $token->replace($settings->get('confirmation_body'), $data), 92 | $settings->get('confirmation_body_format') 93 | ), 94 | ``` 95 | 96 | 97 | ENLACES Y FUENTES 98 | ================= 99 | Documentación SwiftMailer 100 | - https://www.drupal.org/node/1590154 101 | 102 | Inspiración para le hook 103 | - http://code.tutsplus.com/tutorials/using-and-extending-the-drupal-8-mail-api-part-1--cms-23419 104 | 105 | - https://api.drupal.org/api/drupal/core!core.api.php/function/hook_mail_alter/8.2.x 106 | 107 | - https://www.drupal.org/node/2677530#comment-11226949 108 | 109 | Actualizado envio de email 110 | - https://www.lucius.digital/en/blog/sending-html-mails-drupal-89-programmatically-example-drupal-module-including-twig-template 111 | -------------------------------------------------------------------------------- /Back-end/Entidades.md: -------------------------------------------------------------------------------- 1 | ENTIDADES 2 | ======== 3 | 4 | #### Consultas mediante Entidades 5 | 6 | ```php 7 | // Crear entidad 8 | $values = [ 9 | 'name' => 'Jose', 10 | 'lastname' => 'Lopez', 11 | ]; 12 | $Person = Person::create($values); 13 | $Person->save(); 14 | $id = $Person->id(); 15 | 16 | //Eliminar entidad 17 | $Entity = NombreEntidad::load($id); 18 | $Entity->delete(); 19 | 20 | // Actualizar una entidad 21 | $configuration = Configuration::load($id); 22 | $configuration->set('valuation_method', $valuationMethod); 23 | $configuration->set('costs_method', $costMethod); 24 | $configuration->save(); 25 | 26 | // Obtener ids de una entidad con consulta con or condition. 27 | $storage = $this->entityTypeManager->getStorage('alternate_hreflang'); 28 | $query = $storage->getQuery(); 29 | $group = $query 30 | ->orConditionGroup() 31 | ->condition('url_x__uri', $url, '=') 32 | ->condition('url_a__uri', $url, '=') 33 | ->condition('url_b__uri', $url, '='); 34 | $ids = $query 35 | ->condition('status', TRUE, '=') 36 | ->condition($group) 37 | ->execute(); 38 | 39 | // Obtener una entidad mediante consulta 40 | $ids = \Drupal::entityQuery('k_accountplan') 41 | ->condition('iden', $entity, '=') 42 | ->condition('idac', $account->getIdac(), '=') 43 | ->condition('idam', $accountingManagement, '=') 44 | ->sort('number', 'DESC') 45 | ->execute(); 46 | $AccountPlan = AccountPlan::load(reset($ids)); 47 | 48 | // Obtener multiples entidades mediante consulta 49 | $ids = \Drupal::entityQuery('k_accountingentry') 50 | ->condition('idvo', $voucher->getIdvo(), '=') 51 | ->execute(); 52 | $Entries = AccountingEntry::loadMultiple($ids); 53 | foreach ($entries as $entrie) { 54 | ... hacer algo con las entidades ... 55 | } 56 | 57 | // Obtener entidades con tags (Busca las entidades que tienen el tag 'cats') 58 | $query = \Drupal::entityQuery('node') 59 | ->condition('status', 1) 60 | ->condition('field_tags.entity.name', 'cats'); 61 | $nids = $query->execute(); 62 | 63 | // Operadores de consulta 64 | '=', '<>', '>', '>=', '<', '<=', 'STARTS_WITH', 'CONTAINS', 'ENDS_WITH' 65 | 'IN', 'NOT IN', 'IS', 'IS NOT': Esperan un $value en un array de textos del mismo tipo del campo. 66 | 'BETWEEN': Espera un $value en un array de 2 literales del mismo tipo del campo. 67 | 68 | // OR CONDITION 69 | $storage = $this->entityTypeManager->getStorage('node'); 70 | // 2147483647 us timestamp in published_at field when no fill. 71 | $or_group = $storage->getQuery()->orConditionGroup() 72 | ->notExists('published_at') 73 | ->condition('published_at', 2147483647, '='); 74 | $query = $storage->getQuery() 75 | ->condition('type', 'node_type') 76 | ->condition($or_group); 77 | $node_ids = $query->execute(); 78 | 79 | 80 | // Obtener datos de entidades foraneas 81 | $entity->idac->target_id; 82 | $entity->idac->entity->label(); 83 | 84 | // Obtner valor de un atributo de la entidad 85 | $rule->get('variable')->value 86 | 87 | // Guardar imagenes en una entidad 88 | $data = file_get_contents('https://fb-s-b-a.akamaihd.net/h-ak-xpa1/v/t1.0-1/p200x200/15977045_10154309431871267_7175376318146668144_n.jpg?oh=d9e53d50dd85061ce909c3836aa52b09&oe=5925DCAC&__gda__=1499424910_0b04f8498e91f1bff0bbfb6555c8aada'); 89 | $file = file_save_data($data, null, FILE_EXISTS_REPLACE); 90 | 91 | //create an entity 92 | $values = [ 93 | 'name' => 'My new land', 94 | 'photo' => [ <=== this is the field name image of my custom entity 95 | 'target_id' => $file->id(), 96 | 'alt' => 'Hello world' 97 | ], 98 | ]; 99 | $person = DefaultBien::create($values); 100 | $person->save(); 101 | ``` 102 | 103 | #### Codigos útiles 104 | ```php 105 | // Obtener el id del campo por defecto de una imagen media. 106 | $nids = \Drupal::entityQuery('node')->condition('type','')->execute(); 107 | $entity = \Drupal::entityTypeManager()->getStorage('node')->load(reset($nids)); 108 | $default_id_media = $entity->get('media')->getFieldDefinition()->getDefaultValue($entity); 109 | if ($default_id_media) { 110 | $default_id_media = reset($default_id_media)['target_id']; 111 | } 112 | ``` 113 | #### Campos de Entidades 114 | ```php 115 | // String 116 | $fields['name'] = BaseFieldDefinition::create('string') 117 | ->setLabel(t('Name')) 118 | ->setDescription(t('The name of the PriceFactor entity.')) 119 | ->setSettings([ 120 | 'default_value' => '', 121 | 'max_length' => 50, 122 | 'text_processing' => 0, 123 | ]) 124 | ->setDisplayOptions('view', [ 125 | 'label' => 'above', 126 | 'type' => 'string', 127 | 'weight' => -4, 128 | ]) 129 | ->setDisplayOptions('form', [ 130 | 'type' => 'string_textfield', 131 | 'weight' => -4, 132 | ]) 133 | ->setDisplayConfigurable('form', TRUE) 134 | ->setDisplayConfigurable('view', TRUE); 135 | 136 | // Link 137 | $fields['url_test'] = BaseFieldDefinition::create('link') 138 | ->setLabel(t('URL test')) 139 | ->setDescription(t('URL link.')) 140 | ->setSettings([ 141 | 'link_type' => LinkItemInterface::LINK_GENERIC, 142 | 'title' => DRUPAL_DISABLED, 143 | ]) 144 | ->setDisplayOptions('form', [ 145 | 'type' => 'link_default', 146 | 'weight' => 0, 147 | ]) 148 | ->setDisplayConfigurable('form', TRUE); 149 | 150 | 151 | //Lista de strings (Select list) 152 | $fields['test'] = BaseFieldDefinition::create('list_string') 153 | ->setLabel(t('List')) 154 | ->setDescription(t('The list of something.')) 155 | ->setSettings([ 156 | 'max_length' => 60, 157 | 'text_processing' => 0, 158 | 'allowed_values' => [ 159 | 'key_1' => 'labee_1', 160 | ] 161 | ] 162 | ->setDefaultValue('') 163 | ->setDisplayOptions('view', [ 164 | 'label' => 'above', 165 | 'type' => 'string', 166 | 'weight' => 0, 167 | ] 168 | ->setDisplayOptions('form', [ 169 | 'type' => 'options_select', 170 | 'weight' => 0, 171 | ]) 172 | ->setDisplayConfigurable('form', TRUE) 173 | ->setDisplayConfigurable('view', TRUE); 174 | 175 | // Lista de números 176 | iden lista de strings, poner 'list_integer' en lugar de 'list_string' 177 | 178 | //Decimal 179 | $fields['price'] = BaseFieldDefinition::create('decimal') 180 | ->setLabel(t('Price')) 181 | ->setDescription(t('The amount of the entity')) 182 | ->setDisplayOptions('view', [ 183 | 'label' => 'above', 184 | 'type' => 'decimal', 185 | 'weight' => -3, 186 | ]) 187 | ->setDisplayOptions('form', [ 188 | 'type' => 'number', 189 | 'weight' => -3, 190 | ]) 191 | ->setDisplayConfigurable('form', TRUE) 192 | ->setDisplayConfigurable('view', TRUE); 193 | 194 | //Integer 195 | $fields['enum'] = BaseFieldDefinition::create('integer') 196 | ->setLabel(t('Enumeration')) 197 | ->setDescription(t('The order')) 198 | ->setDisplayOptions('view', [ 199 | 'label' => 'above', 200 | 'type' => 'integer', 201 | 'weight' => 0, 202 | ]) 203 | ->setDisplayOptions('form', [ 204 | 'type' => 'number', 205 | 'weight' => 0, 206 | ]) 207 | ->setSetting('size', 'big'); 208 | ->setDisplayConfigurable('form', TRUE) 209 | ->setDisplayConfigurable('view', TRUE); 210 | 211 | //Boolean (se torna tinyint en mysql) 212 | $fields['predefined'] = BaseFieldDefinition::create('boolean') 213 | ->setLabel(t('Predefined')) 214 | ->setDescription(t('Predefined')) 215 | ->setDisplayOptions('form', [ 216 | 'type' => 'boolean_checkbox', 217 | 'settings' => [ 218 | 'display_label' => TRUE, 219 | ], 220 | 'weight' => 0, 221 | ]) 222 | ->setDisplayConfigurable('form', TRUE); 223 | 224 | //Fecha 225 | $fields['date_start'] = BaseFieldDefinition::create('timestamp') 226 | ->setLabel(t('Date start')) 227 | ->setDescription(t('The date start')) 228 | ->setDisplayOptions('view', [ 229 | 'label' => 'adobe', 230 | 'type' => 'timestamp', 231 | 'weight' => 2, 232 | ]) 233 | ->setDisplayOptions('form', [ 234 | 'type' => 'datetime_timestamp', 235 | 'weight' => 2, 236 | ]) 237 | ->setDisplayConfigurable('form', TRUE); 238 | 239 | //Text o String long 240 | $fields['description'] = BaseFieldDefinition::create('string_long') 241 | ->setLabel(t('Description')) 242 | ->setDescription(t('The description of the entity')) 243 | ->setTranslatable(TRUE) 244 | ->setSettings([ 245 | 'default_value' => '', 246 | ]) 247 | ->setDisplayOptions('view', [ 248 | 'label' => 'above', 249 | 'type' => 'string', 250 | 'weight' => 4, 251 | ]) 252 | ->setDisplayOptions('form', [ 253 | 'type' => 'string', 254 | 'weight' => 4, 255 | ]) 256 | ->setDisplayConfigurable('form', TRUE) 257 | ->setDisplayConfigurable('view', TRUE); 258 | 259 | //Referecia a otra entidad 260 | $fields['idstore'] = BaseFieldDefinition::create('entity_reference') 261 | ->setLabel(t('Store')) 262 | ->setDescription(t('The store the kardex')) 263 | ->setRequired(TRUE) 264 | ->setSetting('target_type', 'k_store') 265 | ->setSetting('handler', 'default') 266 | ->setDisplayOptions('view', [ 267 | 'label' => 'above', 268 | 'type' => 'entity_reference', 269 | 'weight' => 0, 270 | ]) 271 | ->setDisplayOptions('form', [ 272 | 'type' => 'entity_reference_autocomplete', 273 | 'settings' => [ 274 | 'match_operator' => 'CONTAINS', 275 | 'size' => 60, 276 | 'autocomplete_type' => 'tags', 277 | 'placeholder' => '_' . t('Store') 278 | ], 279 | 'weight' => 0, 280 | ]) 281 | ->setDisplayConfigurable('form', TRUE) 282 | ->setDisplayConfigurable('view', TRUE); 283 | 284 | //Campo imagen 285 | $fields['photo'] = BaseFieldDefinition::create('image') 286 | ->setSetting('file_extensions', 'png') 287 | ->setSetting ('uri_scheme','public://photos') 288 | ->setLabel(t('Photo')) 289 | ->setDescription(t('Entity photo')) 290 | ->setDefaultValue('') 291 | ->setDisplayOptions('view', [ 292 | 'label' => 'above', 293 | 'type' => 'file', 294 | 'weight' => -4, 295 | ]) 296 | ->setDisplayOptions('form', [ 297 | 'type' => 'file', 298 | 'weight' => -4, 299 | ]) 300 | ->setDisplayConfigurable('form', TRUE) 301 | ->setDisplayConfigurable('view', TRUE); 302 | 303 | //Campo referenciado a taxonomias con botones de selección 304 | $fields ['category'] = BaseFieldDefinition::create ('entity_reference') 305 | ->setLabel(t( 'Category')) 306 | ->setDescription(t('Taxonomi term')) 307 | ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED) 308 | ->setSetting ('target_type','taxonomy_term') 309 | ->setTranslatable (TRUE) 310 | ->setDisplayOptions ('form', [ 311 | 'type' => 'options_buttons', 312 | 'weight' => - 10 , 313 | 'settings' => [ 314 | 'match_operator' => 'CONTAINS' , 315 | 'size' => '60' , 316 | 'placeholder' => '' , 317 | ], 318 | ]) 319 | ->setDisplayConfigurable('form', TRUE) 320 | ->setDisplayConfigurable('view', TRUE); 321 | 322 | //Campo referenciado a taxonomias con autocomplete 323 | $fields ['category'] = BaseFieldDefinition::create ('entity_reference') 324 | ->setLabel(t( 'Category')) 325 | ->setDescription(t('Taxonomi term')) 326 | ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED) 327 | ->setSetting ('target_type','taxonomy_term') 328 | ->setTranslatable (TRUE) 329 | ->setDisplayOptions ('form', [ 330 | 'type' => 'entity_reference_autocomplete', 331 | 'weight' => - 10 , 332 | 'settings' => [ 333 | 'match_operator' => 'CONTAINS' , 334 | 'size' => '60' , 335 | 'autocomplete_type' => 'tags' , 336 | 'placeholder' => '' , 337 | ], 338 | ]) 339 | ->setDisplayConfigurable('form', TRUE) 340 | ->setDisplayConfigurable('view', TRUE); 341 | ``` 342 | 343 | 344 | PROGRAMAR REGISTRO DE ENTIDADES EN TRANSACCIONES 345 | ======= 346 | ```php 347 | $database = \Drupal::database(); 348 | $transaction = $database->startTransaction(); 349 | $id_branch = null; 350 | try { 351 | if(empty($id_branch)) { 352 | throw new \Exception('Empty: Branch Entity id.'); 353 | } 354 | $Branch = Entities::load($id_branch); 355 | $branch_address = $Branch->getAddress(); 356 | 357 | for ($i = 0; $i < 8000; $i++) { 358 | $values = [ 359 | 'entity' => $id_branch, 360 | 'name' => 'Store ' . $i, 361 | 'address' => $branch_address, 362 | ]; 363 | $Store = Store::create($values); 364 | $Store->save(); 365 | } 366 | 367 | } 368 | catch (\Exception $e) { 369 | $transaction->rollback(); 370 | watchdog_exception('nombre_modulo', $e, $e->getMessage()); 371 | throw new \Exception( $e->getMessage(), $e->getCode(), $e->getPrevious()); 372 | } 373 | ``` 374 | 375 | ENLACES Y FUENTES 376 | ================= 377 | Documentación oficial 378 | - https://api.drupal.org/api/drupal/8 379 | 380 | Documentación de la comunidad 381 | - https://www.drupal.org/developing/api/8 382 | 383 | Watchdow drupal 8 384 | - https://www.drupal.org/node/2270941 385 | 386 | Entidades 387 | - http://talks.shawnduncan.org/entity_talk/#/overview 388 | - http://talks.shawnduncan.org/entity_talk/images/Entity.svg 389 | 390 | Tipos de campos 391 | - http://bit.ly/1qhjSQ6 392 | 393 | Entidades traducibles 394 | - https://www.drupal.org/docs/develop/translating-custom-entities -------------------------------------------------------------------------------- /Back-end/EntityTypeManager.md: -------------------------------------------------------------------------------- 1 | EntityTypeManager 2 | ======== 3 | 4 | #### Servicio para realizar consultas a entidades 5 | 6 | Operar sobre el formuario de una entidad 7 | ```php 8 | protected function getBundleForm($entity_type_id, $bundle, $bundle_label, array $form, FormStateInterface $form_state, $bundle_count) { 9 | $entityType = $this->entityTypeManager->getDefinition($entity_type_id); 10 | $entity = $this->entityTypeManager->getStorage($entity_type_id)->create([ 11 | $entityType->getKey('bundle') => $bundle, 12 | ]); 13 | 14 | if (!isset($form[$entity_type_id])) { 15 | $form[$entity_type_id] = [ 16 | '#type' => 'container', 17 | '#tree' => TRUE, 18 | ]; 19 | } 20 | 21 | // If there is no bundle label, the entity has no bundles. 22 | if (empty($bundle_label)) { 23 | $bundle_label = $entityType->getLabel(); 24 | } 25 | $form[$entity_type_id][$bundle] = [ 26 | '#type' => 'details', 27 | '#open' => ($bundle_count === 1), 28 | '#title' => $entityType->getLabel() . ' - ' . $bundle_label, 29 | '#parents' => [$entity_type_id, $bundle], 30 | ]; 31 | 32 | $form_display = EntityFormDisplay::collectRenderDisplay($entity, 'bulk_edit'); 33 | // Build entity form. 34 | $form_display->buildForm($entity, $form[$entity_type_id][$bundle], $form_state); 35 | // Get only the field moderation_state. 36 | $this->getModerationStateForm($form[$entity_type_id][$bundle]); 37 | 38 | return $form; 39 | } 40 | 41 | protected function getModerationStateForm(array &$form) { 42 | $field = 'moderation_state'; 43 | foreach (Element::children($form) as $key) { 44 | if ($key != $field) { 45 | unset($form[$key]); 46 | } 47 | } 48 | } 49 | 50 | public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { 51 | $storage = $form_state->getStorage(); 52 | $bundle_data = $storage['moderation_entity_bundles_data']; 53 | $field = "name_of_field"; 54 | foreach ($bundle_data as $entity_type_id => $bundles) { 55 | $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); 56 | foreach ($bundles as $bundle => $label) { 57 | $form_clone = $form; 58 | $form_clone['#parents'] = [$entity_type_id, $bundle]; 59 | $entity = $this->entityTypeManager->getStorage($entity_type_id)->create([ 60 | $entity_type->getKey('bundle') => $bundle, 61 | ]); 62 | $form_display = EntityFormDisplay::collectRenderDisplay($entity, 'bulk_edit'); 63 | // Extract form values into $entity. 64 | $form_display->extractFormValues($entity, $form_clone, $form_state); 65 | $this->configuration[$entity_type_id][$bundle][$field] = $entity->{$field}->getValue(); 66 | } 67 | } 68 | $this->configuration['_add_values'] = $form_state->getValue('_add_values'); 69 | } 70 | ``` 71 | 72 | ENLACES Y FUENTES 73 | ================= 74 | Documentación oficial 75 | https://api.drupal.org/api/drupal/8 76 | 77 | Documentación de la comunidad 78 | https://www.drupal.org/developing/api/8 79 | -------------------------------------------------------------------------------- /Back-end/Errores.md: -------------------------------------------------------------------------------- 1 | Manejo de errores 2 | === 3 | 4 | #### Error handler 5 | ```php 6 | ``` 7 | 8 | Referencias 9 | === 10 | - https://www.drupal.org/docs/develop/coding-standards/php-exceptions -------------------------------------------------------------------------------- /Back-end/Esquemas.md: -------------------------------------------------------------------------------- 1 | 2 | Esquemas 3 | === 4 | 5 | ENLACES Y FUENTES 6 | ================= 7 | Documentación oficial 8 | + https://www.drupal.org/docs/drupal-apis/configuration-api/configuration-schemametadata -------------------------------------------------------------------------------- /Back-end/Fechas.md: -------------------------------------------------------------------------------- 1 | Fechas 2 | === 3 | 4 | #### Fechas 5 | ``` 6 | // Convertir una fecha a un formato de la isntancia Drupal 7 | format_date($rowKardex->getDate(), 'khipu_short'); //deprecado 8 | \Drupal::service('date.formatter')->format($Service->getDate(), 'khipu_short'); 9 | 10 | // Fecha actual formateado para Drupal 11 | $date = date('Y-m-d H:i:s'); 12 | new DrupalDateTime($date) 13 | 14 | // Conmvertir de formato europeo Y-m-d a un formato configurado en el sitio html_date 15 | use Drupal\Core\Datetime\DrupalDateTime; 16 | 17 | $time = DrupalDateTime::createFromFormat('Y-m-d', $date_string); 18 | $date_formatter = \Drupal::service('date.formatter'); 19 | $date_converted = $date_formatter->format($time->getTimestamp(), 'html_date'); 20 | ``` 21 | -------------------------------------------------------------------------------- /Back-end/Formularios.md: -------------------------------------------------------------------------------- 1 | FORMULARIOS 2 | ======== 3 | 4 | #### Manejo 5 | 6 | ```php 7 | //Obtener todos los elementos de un form_state 8 | foreach ($form_state->getValues() as $key => $value) { 9 | drupal_set_message($key . ': ' . $value); 10 | } 11 | //Obtener un elemento de un form_state 12 | $searched = $form_state->getValue('nombre_elemento_formulario'); 13 | 14 | ``` 15 | 16 | #### Campos de formularios 17 | ```php 18 | // Date 19 | $form['date'] = [ 20 | '#type' => 'date', 21 | '#default_value' => $year . "-" . $month . "-" . $day, 22 | '#weight' => 13, 23 | ]; 24 | 25 | // Textfield con autocompletado 26 | $form['products'] = [ 27 | '#type' => 'textfield', 28 | '#placeholder' => '_' . t('Item'), 29 | '#autocomplete_route_name' => 'k_product.active.autocomplete', 30 | '#weight' => 17, 31 | ]; 32 | 33 | // Datetime 34 | $form['date_validity'] = [ 35 | '#type' => 'datetime', 36 | '#date_date_element' => 'date', 37 | '#date_time_element' => 'time', 38 | '#required' => TRUE, 39 | '#default_value' => "", 40 | '#attributes' => [ 41 | 'placeholder' => '_' . t('Validity date'), 42 | ], 43 | '#weight' => 15, 44 | ]; 45 | 46 | // Select 47 | $form['payment'] = [ 48 | '#type' => 'select', 49 | '#attributes' => [ 50 | 'title' => t('Payment Method') 51 | ], 52 | '#options' => [ 53 | 'CASH' => t('Cash'), 54 | 'CHECK' => t('Check'), 55 | 'TRANSFER' => t('Wire Transfer') 56 | ], 57 | '#default_value' => 'CASH', 58 | ]; 59 | 60 | // Checkboxes 61 | $form['platforms'] = [ 62 | '#title' => $this->t('Platforms:'), 63 | '#type' => 'checkboxes', 64 | '#description' => $this->t('Select platforms to use as social media links.'), 65 | '#options' => ['key_a'=> 'text a', 'key_b'=> 'text b', 'key_c'=> 'text c'], 66 | '#default_value' => ['key_a'], 67 | ]; 68 | 69 | // Radios 70 | $form['frequency_options'] = [ 71 | '#type' => 'radios', 72 | '#title' => $this->t('Select the type to frequency to use.'), 73 | '#options' => [ 74 | 'visit_counts' => $this->t('Use visit counts frequency'), 75 | 'time_frequency' => $this->t('Use time frequency'), 76 | 'pages_counts' => $this->t('Use pages visitor counter frequency'), 77 | 'stay_time' => $this->t('Use visitor stay time frequency'), 78 | ], 79 | "#default_value" => 'visit_counts', 80 | '#weight' => -2, 81 | ]; 82 | 83 | 84 | // Button 85 | $form['minus'] = [ 86 | '#type' => "button", 87 | '#value' => "-", 88 | '#attributes' => [ 89 | 'class' => ['addOperator'], 90 | ], 91 | '#weight' => 97, 92 | ]; 93 | 94 | // Textfield 95 | $form['shortDescription'] = [ 96 | '#type' => 'textfield', 97 | '#default_value' => $shortDescription, 98 | '#size' => 90, 99 | '#maxlength' => 90, 100 | '#attributes' => [ 101 | 'placeholder' => '_' . t('Short Description'), 102 | ], 103 | '#weight' => 1000, 104 | ]; 105 | 106 | // Número telefónico 107 | $form['phone_number'] = [ 108 | '#type' => 'tel', 109 | '#title' => $this->t('Example phone'), 110 | ]; 111 | 112 | // Número 113 | $form['page_counts'] = [ 114 | '#type' => 'number', 115 | '#title' => $this->t('Visited page counter'), 116 | '#description' => $this->t("Examples:
117 | 0 = Show popup after each page visited
118 | 1 = Show popup on the first page visited
119 | n = Show popup on n page visited"), 120 | '#default_value' => 3, 121 | '#attributes' => [ 122 | 'min' => 0, 123 | 'max' => 100, 124 | ], 125 | ]; 126 | 127 | // Textarea 128 | $form['pr']['obs'] = [ 129 | '#type' => 'textarea', 130 | '#placeholder' => '_' . t('Observation'), 131 | '#attributes' => ['title' => t('Observation')], 132 | ]; 133 | 134 | // Texto procesado. 135 | 'confirmation_message' => [ 136 | '#type' => 'processed_text', 137 | '#text' => '', 138 | '#format' => 'basic_html', 139 | ], 140 | 141 | 142 | // Hidden con ramas abiertas(arreglo multidimencional) enviadas cuando el formulario sea guardado. 143 | $form['plugin_configuration'] = [ 144 | '#type' => 'hidden', 145 | '#tree' => TRUE, 146 | '#open' => TRUE, 147 | ] 148 | $form['plugin_configuration'][$id] = [ 149 | '#process' => [[get_class($this), 'processPluginConfiguration']], 150 | '#plugin' => $plugin, 151 | ] 152 | 153 | // Nombre de sistema (machine name) 154 | $form['id'] = [ 155 | '#type' => 'machine_name', 156 | '#default_value' => $importer->id(), 157 | '#machine_name' => [ 158 | 'exists' => '\Drupal\products\Entity\Importer::load', 159 | ], 160 | '#disabled' => !$importer->isNew(), 161 | ]; 162 | 163 | // Enlace url 164 | $form['url'] = [ 165 | '#type' => 'url', 166 | '#default_value' => $importer->getUrl() instanceof Url ? $importer->getUrl()->toString() : '', 167 | '#title' => $this->t('Url'), 168 | '#description' => $this->t('The url to the import resource'), 169 | '#required' => TRUE, 170 | ]; 171 | 172 | // Template twig en línea 173 | $form['answer'] = [ 174 | '#type' => 'inline_template', 175 | '#template' => "{% trans %} Hello {% endtrans %} {{user_name}}", 176 | '#context' => [ 177 | 'user_name' => $user_name, 178 | ], 179 | ]; 180 | 181 | // Elementos tag html 182 | $form['title'] = [ 183 | '#type' => 'html_tag', 184 | '#tag' => 'h2', 185 | '#value' => $this->t('Regret cancellation'), 186 | ]; 187 | $form['intro'] = [ 188 | '#type' => 'html_tag', 189 | '#tag' => 'p', 190 | '#value' => $this->t('Do you confirm that you want keep your membership %subscription instead of cancelling it on %date?', [ 191 | '%subscription' => $subscription_label, 192 | '%date' => $date, 193 | ]), 194 | ]; 195 | 196 | // Picker de color 197 | $form['icon_hovered'] = [ 198 | '#type' => 'color', 199 | '#title' => $this->t('Icon hovered'), 200 | '#maxlength' => 8, 201 | '#size' => 8, 202 | '#default_value' => $data['icon_hovered'], 203 | ]; 204 | 205 | ``` 206 | 207 | #### Estados 208 | Permiten condicionar el comportamiento de un elemento de formulario a partir del estado otro elemento. 209 | ```php 210 | $form['boys'] = [ 211 | '#type' => 'checkbox', 212 | '#title' => $this->t('Do you have boys?'), 213 | ]; 214 | 215 | $form['boys_nomber'] = [ 216 | '#type' => 'textfield', 217 | '#title' => $this->t('How many boys do you have?'), 218 | '#states' => [ 219 | 'visible' => [ 220 | 'input[name="boys"]' => ['checked' => TRUE], 221 | ] 222 | ] 223 | ]; 224 | 225 | ``` 226 | Estados: 227 | - visible 228 | - invisible 229 | - enabled 230 | - disabled 231 | - required 232 | - optional 233 | - checked 234 | - unchecked 235 | - collapsed 236 | 237 | Detonantes: 238 | - checked 239 | - empty 240 | - filled 241 | - unchecked 242 | - expanded 243 | - collapsed 244 | - value 245 | 246 | 247 | #### Webform 248 | Consultas 249 | ```php 250 | $submission_storage = \Drupal::entityTypeManager()->getStorage('webform_submission'); 251 | $ids_ws = $submission_storage->getQuery() 252 | ->accessCheck(FALSE) 253 | ->condition('uuid', $submission_uuid) 254 | ->execute(); 255 | if (count($ids_ws) == 1) { 256 | $id_ws = reset($ids_ws); 257 | $webform_submission = $submission_storage->load($id_ws); 258 | $webform_submission_data = $webform_submission->getData(); 259 | 260 | if ($webform_submission_data['numero_de_socio'] == $codigo_de_socio) { 261 | $email = $webform_submission_data['correo_electronico']; 262 | $whatsapp_number = $webform_submission_data['numero_celular_con_whatsapp']; 263 | $status = TRUE; 264 | } 265 | else { 266 | $status = FALSE; 267 | } 268 | } 269 | 270 | 271 | $select = \Drupal::service('database') 272 | ->select('webform_submission_data', 'wsd') 273 | ->fields('wsd', array('sid')) 274 | ->orderBy('wsd.sid', 'DESC') 275 | ->condition('wsd.webform_id', 'id_formulario', '=') 276 | ->condition('wsd.name', 'nombre_sistema_del_campo', '=') 277 | ->condition('wsd.value', $some_value, '=') 278 | ->execute(); 279 | $results = $select->fetchAll(\PDO::FETCH_COLUMN); 280 | 281 | ``` 282 | 283 | ENLACES Y FUENTES 284 | ================= 285 | Documentación oficial 286 | - https://api.drupal.org/api/drupal/core%21core.api.php/group/form_api/9.1.x 287 | 288 | 289 | Implementar un formulario en un modal llamando desde otro formulario con ajax 290 | - https://www.drupal.org/project/drupal/issues/2934463 291 | 292 | Alterar un formulario extendiendolo 293 | - https://www.foreach.be/blog/how-manipulate-forms-drupal-8 294 | 295 | Sobreescribir la ruta pasando parametros en array 296 | - http://www.impraveen.com/override-route-controller-drupal-8 297 | 298 | Tablas con paginador 299 | - https://zanzarra.com/blog/drupal-custom-pager-and-table-header-sortable-without-sql-query 300 | -------------------------------------------------------------------------------- /Back-end/InyeccionDependencias.md: -------------------------------------------------------------------------------- 1 | Inyección de dependencias 2 | ======== 3 | 4 | #### Servicio para realizar consultas a entidades 5 | 6 | Llamar al servicio 7 | ```php 8 | use Drupal\Core\Entity\EntityTypeManagerInterface; 9 | ``` 10 | 11 | Inyectar el servicio en el constructor. 12 | ```php 13 | * ... 14 | * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager 15 | * Entity type manager. 16 | * ... 17 | */ 18 | public function __construct(..., EntityTypeManagerInterface $entityTypeManager, ...) { 19 | parent::__construct(...); 20 | ... 21 | $this->entityTypeManager = $entityTypeManager; 22 | ... 23 | } 24 | ``` 25 | 26 | Instanciar el servicio al momento de crear el objeto. 27 | ```php 28 | ... 29 | public static function create(..., ContainerInterface $container, ...) { 30 | return new static( 31 | ..., 32 | $container->get('entity_type.manager'), 33 | ... 34 | ); 35 | } 36 | 37 | 38 | // Ejemplo de create sin necesidad de reescribir el constructor. 39 | public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { 40 | $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); 41 | $instance->entityTypeManager = $container->get('entity_type.manager'); 42 | return $instance; 43 | } 44 | ``` 45 | 46 | Utilizar el servicio. 47 | ```php 48 | $entityTypeDefinition = $this->entityTypeManager->getDefinition($entity_type_id); 49 | if ($bundle_key = $entityTypeDefinition->getKey('bundle')) { 50 | $results = $this->entityTypeManager->getStorage('node')->loadByProperties([ 51 | 'nid' => $entity_ids 52 | ]); 53 | foreach ($results as $node) { 54 | $type = $node->getType(); 55 | if (!isset($bundle_data[$entity_type_id][$type])) { 56 | $bundle_data[$entity_type_id][$type] = $bundle_info[$entity_type_id][$type]['label']; 57 | } 58 | } 59 | } 60 | ``` 61 | 62 | ENLACES Y FUENTES 63 | ================= 64 | Documentación oficial 65 | - https://api.drupal.org/api/drupal/8 66 | 67 | Documentación de la comunidad 68 | - https://www.drupal.org/developing/api/8 69 | 70 | La manera correcta de implementar 71 | - https://www.drupal.org/docs/drupal-apis/services-and-dependency-injection/dependency-injection-for-a-form -------------------------------------------------------------------------------- /Back-end/Logs.md: -------------------------------------------------------------------------------- 1 | Logs 2 | === 3 | 4 | #### Watchdog (log de drupal) 5 | ``` 6 | //Guardar un texti en el log (Watchdog) 7 | \Drupal::logger('mi_modulo')->notice("Mi mensaje"); 8 | \Drupal::logger('mi_modulo')->error("Mi mensaje"); 9 | ``` 10 | -------------------------------------------------------------------------------- /Back-end/MVC.md: -------------------------------------------------------------------------------- 1 | MVC 2 | ======== 3 | #### Ruta: en mimodulo/mimodulo.routing.yml 4 | ```yml 5 | mimodulo.nombre_de_la_ruta: 6 | path: /ruta/que-se-requiera 7 | defaults: 8 | _controller: Drupal\mimodulo\Controller\NombreControladorController::nombre_metodo 9 | _title: 'Aqui el título' 10 | requirements: 11 | _permission: mimodulo.nombre_del_permiso 12 | ``` 13 | 14 | #### Permiso: en mimodulo/mimodulo.permissions.yml 15 | ```yml 16 | mimodulo.nombre_del_permiso: 17 | title: "Título del privilegio" 18 | description: "Descripción del privilegio" 19 | restrict access: true 20 | 21 | ``` 22 | 23 | #### Hoock en el módulo: en mimodulo/mimodulo.module 24 | ```php 25 | function mimodulo_theme() { 26 | $theme['nombre_template'] = [ 27 | 'variables' => [ 28 | 'variable_1' => NULL, 29 | 'variable_n' => NULL 30 | ], 31 | 'template' => 'nombre_template', 32 | ]; 33 | return $theme; 34 | } 35 | ``` 36 | 37 | #### Controlador: en mimodulo/src/Controller/NombreControladorController.php 38 | ```php 39 | 'nombre_template', 68 | '#variable_1' => $x, 69 | '#variable_n' => $y, 70 | '#cache' => [ 71 | 'max-age' => 0, 72 | ], 73 | ]; 74 | } 75 | 76 | } 77 | ``` 78 | 79 | #### Template: en mimodulo/templates/nombre_template.html.twig 80 | ```html 81 |
82 | 83 |

{{ audio }}

84 |

{% trans %} List of {{ variable_1 }} {% endtrans %}

85 | 86 |
    87 | {% for item in variable_n %} 88 |
  • {{ item.name }}
  • 89 | {% endfor %} 90 |
91 | 92 |
93 | ``` 94 | 95 | 96 | 97 | ENLACES Y FUENTES 98 | ================= 99 | -------------------------------------------------------------------------------- /Back-end/Mensajes.md: -------------------------------------------------------------------------------- 1 | Mensajes 2 | === 3 | 4 | #### Mensajes a la interface del usuario 5 | ```php 6 | //Mensajes del sistema 7 | \Drupal::messenger()->addMessage(t('An error occurred and processing did not complete.'), 'error'); 8 | 9 | \Drupal::messenger()->addStatus(t('This is a successful message.')); 10 | \Drupal::messenger()->addWarning(t('This is a warning message.')); 11 | \Drupal::messenger()->addError(t('This is an error message.')); 12 | ``` 13 | 14 | #### Mensajes al sistema de logs (Whatchdog) 15 | ```php 16 | // Noticias 17 | \Drupal::logger('mi_modulo')->notice($message); 18 | 19 | // Errores 20 | \Drupal::logger('mi_modulo')->error($message); 21 | ``` -------------------------------------------------------------------------------- /Back-end/Migraciones/Migrate.md: -------------------------------------------------------------------------------- 1 | Migrate 2 | ======== 3 | 4 | #### Ejemplos de uso de plugins. 5 | 6 | Obtener el arbol de términos de una taxonomía. 7 | ``` 8 | ``` 9 | 10 | 11 | 12 | ENLACES Y FUENTES 13 | ================= 14 | Documentación oficial 15 | - https://www.drupal.org/docs/8/api/migrate-api/migrate-process-plugins 16 | 17 | Lista de los plugins 18 | - https://www.drupal.org/docs/8/api/migrate-api/migrate-process-plugins/list-of-core-migrate-process-plugins 19 | 20 | Explicacion de migration_lookup, entity_lookup, entity_generate 21 | - https://understanddrupal.com/articles/understanding-entitylookup-and-entitygenerate-process-plugins-migrate-tools -------------------------------------------------------------------------------- /Back-end/Migraciones/MigrateAPI.md: -------------------------------------------------------------------------------- 1 | Migrate Plus 2 | ======== 3 | 4 | 5 | 6 | #### Enlaces y fuentes. 7 | Migrate API 8 | - https://www.drupal.org/docs/drupal-apis/migrate-api 9 | 10 | Migrando usando query sql para obtener los datos fuente 11 | - https://www.drupal.org/docs/8/api/migrate-api/migrate-source-plugins/migrating-data-from-a-sql-source 12 | 13 | Ejemplos de migraciones: nodos, taxonomias, terminos, usuarios, archivos e imágenes, media, configuraciones, commerce. 14 | - https://www.drupal.org/docs/drupal-apis/migrate-api/migrate-destination-plugins-examples 15 | 16 | Ejemplos básicos de process 17 | - https://www.drupal.org/docs/8/api/migrate-api/migrate-process-plugins/migrate-process-overview 18 | 19 | Lista de plugins para process 20 | - https://www.drupal.org/docs/8/api/migrate-api/migrate-process-plugins/list-of-core-migrate-process-plugins -------------------------------------------------------------------------------- /Back-end/Migraciones/d7-a-d8.md: -------------------------------------------------------------------------------- 1 | Migrar un sitio completo de drupal 7 a drupal 8 2 | ======== 3 | 4 | #### Resumen del proceso 5 | ``` 6 | Preparar sitio D7 > Prepara sitio D8 > Migrar > Configuraciones manuales. 7 | ``` 8 | 9 | #### Preparar D7 para ser migrado. 10 | ``` 11 | 1. Tener el sitio en local. 12 | 2. Identificar los módulos contribuidos a ser migrados. 13 | admin/reports/updates 14 | Para cada módulo contestar 15 | Necesito este módulo en D8? 16 | Si => Está el módulo incluido en el core de D8? 17 | Si => Utilizarlo. 18 | No => Existe este módulo para D8? 19 | Si => Utilizarlo. 20 | No => Existe otro módulo para D8 que cumpla la misma función? 21 | Si => Agregarlo manualmente. 22 | No => Resignar o implementar una solución custom. Sin embargo posiblemente esta funcionalidad ya no está vigente. 23 | 3. Revizar y conocer los problemas conocidos que tiene actualmente el proceso en 24 | https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#s-drupal-7-to-8 25 | 4. Actualizar el core y todos los módulos contribuidos. 26 | 5. Verificar el acceso público(navegador) a los archivos públicos (public files) 27 | ``` 28 | 29 | #### Preparar D8 par la migración. 30 | ``` 31 | 1. Tener una instalación limpia(sin contenido ni configuraciones adicionadas). 32 | 2. Tener acceso a la base de datos de D7 y D8 desde el mismo host. 33 | En D8 configurar settings.php 34 | $databases['default']['default'] = [ 35 | 'database' => 'd8db', 36 | 'username' => 'd8user', 37 | 'password' => 'd8pass', 38 | 'prefix' => '', 39 | 'host' => 'localhost', 40 | 'port' => '3306', 41 | 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', 42 | 'driver' => 'mysql', 43 | ]; 44 | 45 | $databases['migrate']['default'] = [ 46 | 'database' => 'd7db', 47 | 'username' => 'd7user', 48 | 'password' => 'd7pass', 49 | 'prefix' => '', 50 | 'host' => 'localhost', 51 | 'port' => '3306', 52 | 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', 53 | 'driver' => 'mysql', 54 | ]; 55 | 3. Si se necesitan migrar archivos privados de D7 56 | Estos deben ser accesibles desde D8 y se deben configurar file_private_path en settings.php antes de corres el upgrade. 57 | 4. Instalar Drush 8 o 9 en el proyecto. 58 | Si has instalado drupal mediante composer, yá tienes drush como una dependencia en composer.json 59 | Si nó puedes ejecutar: 60 | $ composer require drush/drush 61 | 5. Instalar los siguientes módulos: 62 | - migrate (core) 63 | - migrate_drupal (core) 64 | - migrate_drupal_ui - Opcional, si se va hacer la migración por UI. 65 | - migrate_drupal_multilingual - Opcional, si es un sitio multiidiomas. 66 | - migrate_upgrade - Soporte para comandos drush de actualización de versión de drupal. 67 | - migrate_plus - Extensiones útiles al core de migrate. 68 | - migrate_tools - Comandos drush a utilizar en la migración. 69 | 6. Habilitar todos los módulos homologados de D7 en D8. 70 | 7. Colocar el sitio en modo mantenimiento. 71 | ``` 72 | 73 | #### Migrar mediante navegador web. 74 | ``` 75 | Recomendado si eres novato en migraciones con Drupal. 76 | 1. Ir a la interface gráfica: /upgrade 77 | Seguir el procedimiento indicado. 78 | ``` 79 | 80 | #### Migrar mediante DRUSH. 81 | ``` 82 | Es la manera más robusta y veloz, pero requiere módulos adicionales y configuraciones. 83 | 84 | UTILIZANDO COMANDOS DIRECTOS 85 | 2. Generar las migraciones usando migrate-upgrade. 86 | Ver la lista de migraciones posibles. 87 | $ drush migrate-status 88 | 89 | Ejecutar todas las migraciones. 90 | drush migrate-import --all 91 | 92 | Generar la migración completa en el sitio D7 desde el espacio D8 93 | $ drush migrate-upgrade 94 | 95 | Si se necesita sólo migrar las configuraciones. 96 | $ drush migrate-upgrade --legacy-db-url=mysql://user:password@server/db --legacy-root=http://url-del-sitio-d7.com --configure-only 97 | 98 | Ejecutar migraciones selectivamente. 99 | drush migrate-import 100 | 101 | 102 | UTILIZANDO MANIFIESTOS 103 | 1. Instalar el módulo migrate_manifest 104 | 105 | Obtener la lista completa de migraciones en un archivo yml 106 | # drush migrate-template-list //drush 8 107 | # drush migrate:template:list //drush 9 108 | 109 | 2. Colocar el archivo yml en en un lugar accesible por drush. (de preferencia dentro del versionamiento de git) 110 | 111 | 3. Asegurarse de que todos los módulos usados en el manifiesto de migración existen y están habilitados en D8. 112 | 113 | 4. Ejecutar la las migraciones especificadas en el manifiesto. 114 | $ drush migrate-manifest --legacy-db-url=mysql://d7user:d7pass@localhost/drupal_7 manifest.yml 115 | ``` 116 | 117 | #### Configuraciones manuales. 118 | ``` 119 | Luego de migrar el contenido y las configuraciones. Es muy posible que hayan módulos que instalar, configuraciones que completar. 120 | ``` 121 | 122 | ENLACES Y FUENTES 123 | ================= 124 | Documentación oficinal de drupal 125 | - https://www.drupal.org/docs/8/upgrade/upgrading-from-drupal-6-or-7-to-drupal-8-and-newer 126 | 127 | Lista de módulos útiles para la migración 128 | - https://www.drupal.org/docs/8/upgrade/drupal-8-migrate-modules 129 | 130 | Actualizar mediante navegador web 131 | - https://www.drupal.org/docs/8/upgrade/upgrade-using-web-browser 132 | 133 | Actualizar mediante drush 134 | - https://www.drupal.org/docs/8/upgrade/upgrade-using-drush 135 | 136 | -------------------------------------------------------------------------------- /Back-end/Migraciones/importar-contenido.md: -------------------------------------------------------------------------------- 1 | Migrar contenido 2 | ======== 3 | #### Módulos involucrados. 4 | ``` 5 | migrate - Framework de migraciones hacia Drupal(nodes, users, files, terms, comments) desde otras fuentes. 6 | migrate_tools - Kit de herramientas para ejecutar y administrar migraciones (status, import, rollback, stop, reset-status, messages, fiedls-source) 7 | migrate_plus - Extensiones al core de migrate (Configuration entities, extensiones del API como PREPARE_ROW, etc.) 8 | migrate_source_csv - Funcionalidad completa para importar archivos CSV. 9 | config_devel - Ayuda a configrar el entorno para importaciones y exportaciones automáticas. 10 | ``` 11 | #### Proceso. 12 | ``` 13 | Crear el tipo de contenido. 14 | Crear un módulo nuevo. 15 | Crear la estructura de archivos. 16 | Crear el archivo de datos csv. 17 | Crear el archivo de importación yml. 18 | Testear la migración (comandos drush) 19 | ``` 20 | #### Comandos drush. 21 | ``` 22 | Lista de todas las migraciones disponibles 23 | $ drush ms 24 | 25 | Realizar la importación de una migración 26 | $ drush mi 27 | ``` 28 | #### Todo lo que se puede hacer. 29 | ``` 30 | - Importar archivos pdf, imágenes, etc. 31 | - Importar en diferentes tipos de campos. 32 | - Importar en entidades relacionadas. 33 | - Combinaciones de plugibs estándar (explode, default_value, concat, etc.) 34 | - Crear plugins propios. 35 | ``` 36 | 37 | ENLACES Y FUENTES 38 | ================= 39 | Buen video explicativo que muestra como usar migrate 40 | https://www.youtube.com/watch?v=zZLL02GkP9E&t=1372s 41 | -------------------------------------------------------------------------------- /Back-end/Multiidiomas.md: -------------------------------------------------------------------------------- 1 | Multiidiomas 2 | ======== 3 | #### Configurar un sitio multi-idiomas 4 | ```md 5 | Instalar los módulos: 6 | - Configuration Translation.- Traducir las configuraciones. (Ttulo de un bloque, etc) 7 | - Content translation.- Traducir entidades de contenido. (Nodos, Media, Taxonomías, etc) 8 | - Interface translation.- Traducir la interface de usuario. 9 | - Language.- Configurar los idiomas disponibles y su aplicación al contenido. 10 | 11 | 1. Agregar idiomas. 12 | - /admin/config/regional/language 13 | 14 | 2. Configurar detección y selección. 15 | - /admin/config/regional/language/detection 16 | 17 | 3. Agregar el selector de idiomas. 18 | - Utilizar el bloque "Language switche" 19 | 20 | 4. Configurar elementos que van a ser traducibles. 21 | - /admin/config/regional/content-language 22 | - Lista de entidades que van a ser traducibles. 23 | - Es necesaro elegir cuales(content, taxonomies, etc) y sus elementos internos como los campos. 24 | 25 | 5. Traducir la interface gráfica: 26 | - /admin/config/regional/translate 27 | Permite traducir todos los textos del código fuente de drupal. 28 | - Configuración YML. 29 | - Código PHP. 30 | - Código Javascript. 31 | 32 | 6. Traducir configuración. 33 | - /admin/config/regional/config-translation 34 | Views, Bloques, Formularios, Tipos de contenidos, Formatos de fecha, Estilos de imágen, etc. 35 | ``` 36 | 37 | #### Programar etiquetas en otros idiomas 38 | 39 | ```php 40 | // En php 41 | t('Instalación', array(), array('langcode' => 'es', 'context' => 'khipu' )) 42 | 43 | // En javascript 44 | Drupal.t('Delirant')) 45 | Drupal.t('Mayo', {}, {context: "Calendario", 'langcode': 'es'}); 46 | ``` 47 | 48 | ```twig 49 | // En twig 50 | {{ 'Free carita gift box'|t }} 51 | 52 | 57 | 58 | 61 | 62 | 63 | ``` 64 | 65 | ```yml 66 | // En yml 67 | quotation.proposal: 68 | path: '/quotations/proposal' 69 | defaults: 70 | _form: '\Drupal\inventory_io\Form\ProposalForm' 71 | _title: 'Propuesta' 72 | _title_context: 'khipu' 73 | langcode: es 74 | requirements: 75 | _permission: quotation.proposal 76 | ``` 77 | 78 | #### Manipulación programática 79 | Utilizar version traducida de una entidad. 80 | 81 | ```php 82 | $category = Term::load($id_category); 83 | $curr_langcode = \Drupal::languageManager()->getCurrentLanguage(\Drupal\Core\Language\LanguageInterface::TYPE_CONTENT)->getId(); 84 | $translated = \Drupal::service('entity.repository')->getTranslationFromContext($category, $curr_langcode); 85 | ``` 86 | 87 | Utilizar el manejador de lenguaje del core 88 | ```php 89 | $language_manager = \Drupal::languageManager(); 90 | $site_default_langcode = $language_manager->getDefaultLanguage()->getId(); 91 | 92 | // Obtener las configuraciones de un lenguage 93 | $config_name = basename($file_name, '.yml'); 94 | $config = $language_manager->getLanguageConfigOverride($langcode, $config_name); 95 | // Ejemplo 96 | $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId(); 97 | $config_name = basename('role_expire_notification.config', '.yml'); 98 | $config = \Drupal::languageManager()->getLanguageConfigOverride($langcode, $config_name); 99 | $configuration_values = $config->get('role_expire_notification_points'); 100 | ``` 101 | 102 | 103 | ENLACES Y FUENTES 104 | ================= 105 | Documentación traducción de código drupal 106 | - https://www.drupal.org/developing/api/8/localization 107 | 108 | Documentación traducción twig 109 | - http://symfony.com/doc/current/book/translation.html 110 | -------------------------------------------------------------------------------- /Back-end/Nodos.md: -------------------------------------------------------------------------------- 1 | Nodos 2 | ======== 3 | #### Query para obtener datos 4 | ```php 5 | // Obtener un nodo con consulta. 6 | $node_storage = $this->entityTypeManager->getStorage('node'); 7 | $ids = $node_storage->getQuery() 8 | ->condition('title', $source_title) 9 | ->condition('type', 'quiz') 10 | ->execute(); 11 | if (!empty($ids)) { 12 | $node_id = reset($ids); 13 | $node = $node_storage->load($node_id); 14 | } 15 | 16 | // Obtener el entity_type_manager sin injectar como servicio. 17 | $node_storage = \Drupal::entityTypeManager()->getStorage('node'); 18 | 19 | 20 | // Obtener todos los nodos de un tipo de contenido 21 | $nids = \Drupal::entityQuery('node')->condition('type','my_custom_type')->execute(); 22 | $nodes = \Drupal\node\Entity\Node::loadMultiple($nids); 23 | 24 | ``` 25 | 26 | 27 | ENLACES Y FUENTES 28 | ================= 29 | -------------------------------------------------------------------------------- /Back-end/PDF.md: -------------------------------------------------------------------------------- 1 | PDF 2 | ======== 3 | 4 | #### Generar archivo PDF 5 | 6 | ```php 7 | use Dompdf\Dompdf; 8 | use Drupal\Core\Link; 9 | use Drupal\Core\Url; 10 | 11 | 12 | /** @var \Drupal\Core\Template\TwigEnvironment $twig */ 13 | $twig = \Drupal::service('twig'); 14 | $dompdf = new Dompdf(); 15 | $url = \Drupal::request()->getSchemeAndHttpHost(); 16 | 17 | // Predefinimos el destino del archivo para acceso público. 18 | $wrapper = 'public'; 19 | $rand = substr(hash('ripemd160', uniqid()), 0, 8); 20 | $filename = 'nombre_del_archivo'. '-' . $rand . '.' . 'pdf'; 21 | $destination = $wrapper . '://' . $filename; 22 | 23 | $dompdf->loadHtml($twig->render('@nombre_modulo_theme/folder_del_template/nombre_template.html.twig', [ 24 | 'parametro_1_para_twig' => 'valor_1', 25 | 'parametro_3_para_twig' => 'valor_2', 26 | ])); 27 | $dompdf->render(); 28 | 29 | sendToFileWithPredestination($dompdf->output(), $destination); 30 | 31 | function sendToFileWithPredestination(string $output, string $destination) { 32 | if (!empty($output) && !empty($destination)) { 33 | $file = file_save_data($output, $destination, FileSystemInterface::EXISTS_REPLACE); 34 | $file->setTemporary(); 35 | $file->save(); 36 | 37 | // Si fuese nesecario sacar un enlace al archivo. 38 | $file_url = Url::fromUri( 39 | file_create_url($file->getFileUri()), 40 | [ 41 | 'attributes' => ['target' => '_blank'], 42 | 'absolute' => TRUE, 43 | ] 44 | ); 45 | $link = Link::fromTextAndUrl($this->t('Click here'), $file_url); 46 | $this->messenger()->addStatus($this->t('Export file created, @link to download.', ['@link' => $link->toString()])); 47 | } 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /Back-end/Plugins/API_Plugin.md: -------------------------------------------------------------------------------- 1 | Plugin API 2 | ======== 3 | 4 | 5 | 6 | ### Enlaces 7 | 8 | Documentación oficial 9 | - https://www.drupal.org/docs/drupal-apis/plugin-api 10 | -------------------------------------------------------------------------------- /Back-end/Plugins/FilterPlugin.md: -------------------------------------------------------------------------------- 1 | FilterPlugin 2 | ======== 3 | 4 | #### Filtro aplicable a un campo para agregar target_blank a todos los enlaces del contenido 5 | ``` 6 | namespace Drupal\mi_modulo\Plugin\Filter; 7 | 8 | use Drupal\Component\Utility\Html; 9 | use Drupal\filter\FilterProcessResult; 10 | use Drupal\filter\Plugin\FilterBase; 11 | use Drupal\Core\Url; 12 | 13 | /** 14 | * Provides a ExternalLinkFilter filter. 15 | * 16 | * @Filter( 17 | * id = "external_link", 18 | * title = @Translation("External links processor"), 19 | * description = @Translation("Updates links with neccessary attribute."), 20 | * type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE 21 | * ) 22 | */ 23 | class ExternalLinkFilter extends FilterBase { 24 | 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | public function process($text, $langcode) { 29 | $result = new FilterProcessResult($text); 30 | if (strpos($text, 'href=') !== FALSE) { 31 | $dom = Html::load($text); 32 | $xpath = new \DOMXPath($dom); 33 | foreach ($xpath->query('//a[@href]') as $element) { 34 | $link_uri = $element->getAttribute('href'); 35 | if ($link_uri == '') { 36 | $link_uri = Url::fromRoute('')->toString(); 37 | $element->setAttribute('href', $link_uri); 38 | } 39 | else { 40 | $base_uri = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; 41 | if (str_contains($link_uri, $base_uri) === FALSE) { 42 | $element->setAttribute('target', '_blank'); 43 | $element->setAttribute('rel', 'noopener'); 44 | } 45 | } 46 | } 47 | $result->setProcessedText(Html::serialize($dom)); 48 | } 49 | 50 | return $result; 51 | } 52 | 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /Back-end/Plugins/LanguageNegotiation.md: -------------------------------------------------------------------------------- 1 | Laanguage negotiation 2 | ======== 3 | 4 | #### Filtro aplicable a un campo para agregar target_blank a todos los enlaces del contenido 5 | ``` 6 | namespace Drupal\mi_modulo\Plugin\LanguageNegotiation; 7 | 8 | use Drupal\language\LanguageNegotiationMethodBase; 9 | use Symfony\Component\HttpFoundation\Request; 10 | 11 | /** 12 | * Custom class for identifying language. 13 | * 14 | * @LanguageNegotiation( 15 | * id = Drupal\mi_modulo\Plugin\LanguageNegotiation\LanguageNegotiationAnonymous::METHOD_ID, 16 | * weight = -99, 17 | * name = @Translation("Anonymous Language always English"), 18 | * description = @Translation("Language based on anonymous restriction to view always the website an English."), 19 | * ) 20 | */ 21 | class LanguageNegotiationAnonymous extends LanguageNegotiationMethodBase { 22 | 23 | /** 24 | * The language negotiation method id. 25 | */ 26 | const METHOD_ID = 'language-anonymous'; 27 | 28 | /** 29 | * {@inheritdoc} 30 | */ 31 | public function getLangcode(Request $request = NULL) { 32 | if ($this->currentUser->isAnonymous()) { 33 | $langcode = 'en'; 34 | return $langcode; 35 | } 36 | } 37 | 38 | } 39 | ``` -------------------------------------------------------------------------------- /Back-end/Rest.md: -------------------------------------------------------------------------------- 1 | REST 2 | ======== 3 | 4 | #### Generación mediante la consola 5 | ``` 6 | // Genera la clase que permite gestionar un servicio mediante los métodos GET, PUT, POST, DELETE, PATCH, HEAD, OPTIONS 7 | $ drupal generate:plugin:rest:resource 8 | Cuando pida 'Enter the plugin rest resource url' se puede poner /ruta/{parametros} 9 | ``` 10 | 11 | ### Habilitar el recurso 12 | ``` 13 | Instalar el módulo REST UI 14 | https://www.drupal.org/project/restui 15 | 16 | - Habilitar el recurso. 17 | /admin/config/services/rest 18 | 19 | - Activar privilegios para los roles indicados. 20 | /admin/people/permissions 21 | ``` 22 | 23 | ### Acceder al recurso 24 | ``` 25 | Por URL 26 | /dblog/1?_format=json 27 | 28 | Usando postman 29 | 30 | ``` 31 | 32 | ### Ejemplo conexión uso rest post desde Python 33 | ```Python 34 | import requests 35 | import json 36 | 37 | user_drupal = "algun_usuario" 38 | pass_drupal = "alguna_clave" 39 | url_base = 'http://www.misitio.com' 40 | 41 | # Logueo en drupal. El logueo se debe realizar una sola vez, luego con esta sesión se debe realizar las operaciones. 42 | user_datas = {"name":user_drupal,"pass":pass_drupal} 43 | data_json = json.dumps(user_datas) 44 | response_login = requests.post(url_base + '/user/login?_format=json', data=data_json) 45 | data_result = json.loads(response_login.text) 46 | csrf_token = data_result['csrf_token'] 47 | 48 | # Enviar un json para registro mediante post 49 | data = { 50 | "voucher": 51 | { 52 | "class":"normal", 53 | "date":1508891700, 54 | "gloss":"Asiento de prueba", 55 | "type":"INCOME", 56 | "entry_subtype":"PAYMENT", 57 | "state":"REGISTERED" 58 | } 59 | } 60 | data_json = json.dumps(data) 61 | header = {'Content-Type':'application/json','X-CSRF-Token':csrf_token} 62 | 63 | client = requests.session() 64 | client.headers.update(header) 65 | client.auth = (user_drupal,pass_drupal) 66 | 67 | response_post = client.post(url_base + '/url_al_servicio_post?_format=json', data=data_json) 68 | print (response_post.text) 69 | ``` 70 | 71 | #### Referencias 72 | ``` 73 | Ejmplo con GET y POST 74 | https://github.com/DrupalBolivia/RESTFul-web-services/blob/master/rest_example/src/Plugin/rest/resource/RestExampleResource.php 75 | 76 | Documentación 77 | https://www.drupal.org/docs/8/api/restful-web-services-api/restful-web-services-api-overview 78 | ``` 79 | 80 | -------------------------------------------------------------------------------- /Back-end/Restricciones.md: -------------------------------------------------------------------------------- 1 | Restricciones 2 | === 3 | 4 | #### Referencias 5 | ``` 6 | Documentación oficial. 7 | - https://www.drupal.org/docs/drupal-apis/entity-api/entity-validation-api/defining-constraints-validations-on-entities-andor-fields 8 | ``` 9 | -------------------------------------------------------------------------------- /Back-end/Rutas.md: -------------------------------------------------------------------------------- 1 | Rutas 2 | ======== 3 | #### Obtener rutas del proyecto 4 | Obtener el host. Ej: drupal9.local 5 | ```php 6 | $host = \Drupal::request()->getHost(); 7 | ``` 8 | 9 | Obtener ruta base completa. Ej: https://drupal8.local 10 | ```php 11 | $base_uri = \Drupal::request()->getSchemeAndHttpHost(); 12 | ``` 13 | 14 | Obtener la ruta actual 15 | ```php 16 | $current_path = \Drupal::service('path.current')->getPath(); 17 | ``` 18 | 19 | #### Crear una ruta 20 | En el archivo miarchivo.routing.yml 21 | ```yml 22 | sale.onlyform.add: 23 | path: '/sales/sales-add' 24 | defaults: 25 | _form: '\Drupal\sales\Form\addsaleForm' 26 | _title: 'Sales' 27 | requirements: 28 | _permission: sale.onlyform.add 29 | ``` 30 | En el archivo miarchivo.permission.yml 31 | ```yml 32 | sale.onlyform.add: 33 | title: 'Add Sale' 34 | description: 'Add Sale' 35 | restrict access: true 36 | ``` 37 | #### Crear urls 38 | ```php 39 | use Drupal\Core\Url; 40 | $Url = new Url($route_name, $params)​; 41 | 42 | // O mediante el método estático de la url 43 | $url = Url::fromRoute($route_name, $params)​ 44 | // Ejemplo 45 | $url = Url::fromRoute('view.glossary_terms.glossary_page', ['arg_0' => 'all'])->toString(); 46 | ``` 47 | #### Obtener una url 48 | ```php 49 | // Obtener la ruta actual 50 | $currentRoute = \Drupal::routeMatch(); 51 | 52 | // o usando como base el nombre de la ruta 53 | $path = Url::fromRoute($route_name); 54 | 55 | // Sin una ruta como base 56 | use Drupal\Core\Url; 57 | $Url = Url::fromUri('internal:/mypath/to/style.css'); 58 | ``` 59 | 60 | #### Obtener nombre routing de la ruta actual 61 | ```php 62 | $url_object = \Drupal::service('path.validator')->getUrlIfValid(\Drupal::service('path.current')->getPath()); 63 | $route_name = $url_object->getRouteName(); 64 | ``` 65 | 66 | #### Parametros 67 | ```php 68 | // Obtener un parametro 69 | $currentRoute = \Drupal::routeMatch(); 70 | $query = $currentRoute->getParameter('nombre_parametro'); 71 | 72 | // Vs 73 | 74 | $query = \Drupal::request()->query->get('name'); 75 | ``` 76 | 77 | #### Redireccionamiento 78 | ```php 79 | use Symfony\Component\HttpFoundation\RedirectResponse; 80 | 81 | $response = new RedirectResponse("quotation?id=" . $idQuotationClient); 82 | $response->send(); 83 | 84 | $path = Url::fromRoute('mi_nombre_ruta')->toString(); 85 | $response = new RedirectResponse($path); 86 | $response->send(); 87 | 88 | // Para rutas externas usar TrustedRedirectResponse 89 | ``` 90 | 91 | ### route_name de vistas 92 | ``` 93 | view.VIEW_MACHINE_NAME.PAGE_MACHINENAME 94 | view.$view_id.$display_id" 95 | ``` 96 | 97 | 98 | #### Referencias 99 | - Posibilidades de las rutas: 100 | https://www.drupal.org/node/2092643 101 | 102 | - Cheatsheet 103 | https://cryptic.zone/blog/drupal-8-cheatsheet-developers 104 | 105 | - Redireccionamiento 106 | https://x-team.com/blog/drupal-goto/ 107 | 108 | - Links, URLs, URIs 109 | https://www.hashbangcode.com/article/drupal-9-programmatically-creating-and-using-urls-and-links 110 | -------------------------------------------------------------------------------- /Back-end/Schemas.md: -------------------------------------------------------------------------------- 1 | Schemas 2 | ======== 3 | 4 | #### Debug con drush 5 | Ver todas las incidencias 6 | ``` 7 | $ drush config:inspect 8 | ``` 9 | 10 | Ver detalle de una configuración 11 | ``` 12 | $ drush config:inspect --detail page_manager.page_variant.site_template-default 13 | ``` 14 | 15 | #### Reparar el mapping 16 | ``` 17 | function mi_modulo_config_schema_info_alter(&$definitions) { 18 | // @todo: Remove once https://www.drupal.org/project/menu_multilingual/issues/2956990 is fixed. 19 | if (isset($definitions['block.settings.system_menu_block:*.third_party.menu_multilingual']['mapping']) && isset($definitions['block.settings.system_menu_block:*']['mapping'])) { 20 | $definitions['block.settings.system_menu_block:*']['mapping'] = array_merge($definitions['block.settings.system_menu_block:*']['mapping'], $definitions['block.settings.system_menu_block:*.third_party.menu_multilingual']['mapping']); 21 | } 22 | } 23 | ``` 24 | 25 | ENLACES Y FUENTES 26 | ================= 27 | Documentación oficial 28 | https://www.drupal.org/docs/drupal-apis/configuration-api/configuration-schemametadata 29 | 30 | -------------------------------------------------------------------------------- /Back-end/Servicios.md: -------------------------------------------------------------------------------- 1 | SERVICIOS 2 | ======== 3 | 4 | #### Acceder a un servicio 5 | ```php 6 | // Listar todos los servicios disponibles. 7 | \Drupal::getContainer()->getServiceIds() 8 | 9 | $my_service = \Drupal::service('my_service_name'); 10 | 11 | // Dentro un controlador se puede acceder mediante su contenedor 12 | class MyController extends ControllerBase { 13 | public function myMethod() { 14 | $container = $this->container(); 15 | $my_service = $container->get('my_service_name'); 16 | } 17 | } 18 | 19 | // Llamando a los métodos estáticos de la clase Drupal para acceder a algunos servicios 20 | \Drupal::entityManager(); 21 | \Drupal::database(); 22 | \Drupal::urlGenerator(); 23 | \Drupal::translation(); 24 | ``` 25 | #### Inyectar servicios 26 | ``` 27 | // en desarrollo 28 | ``` 29 | 30 | CREAR SERVICIOS 31 | === 32 | 33 | #### Ruta 34 | En services.yml 35 | ``` 36 | services: 37 | mymodule.myservice: 38 | class: Drupal\my_module\MyService 39 | arguments: ['@entity.query'] 40 | ``` 41 | #### Clase 42 | En services.yml 43 | ``` 44 | class MyService { 45 | protected $entityQuery; 46 | 47 | public function __construct(QueryFactory $entity_query) { 48 | $this->entityQuery = $entity_query; 49 | } 50 | } 51 | ``` 52 | 53 | INYECTAR SERVICIOS 54 | === 55 | ```php 56 | use Drupal\Core\DependencyInjection\ContainerInjectionInterface; 57 | use Symfony\Component\DependencyInjection\ContainerInterface; 58 | use Drupal\Core\Entity\Query\QueryFactory; 59 | 60 | class MyController extends ControllerBase implements ContainerInjectionInterface { 61 | protected $entityQuery; 62 | 63 | /** 64 | * Constructor. Stores injected services. 65 | */ 66 | public function __construct(QueryFactory $entity_query) { 67 | $this->entityQuery = $entity_query; 68 | } 69 | 70 | /** 71 | * {@inheritdoc} 72 | */ 73 | public static function create(ContainerInterface $container) { 74 | return new static( 75 | $container->get('entity.query') 76 | ); 77 | } 78 | } 79 | ``` 80 | 81 | #### Referencias 82 | Cheatsheet 83 | - https://cryptic.zone/blog/drupal-8-cheatsheet-developers 84 | 85 | Sobrescribir servicios 86 | - https://www.bounteous.com/insights/2017/04/19/drupal-how-override-core-drupal-8-service/ 87 | -------------------------------------------------------------------------------- /Back-end/Sesiones: -------------------------------------------------------------------------------- 1 | Sesiones 2 | ======== 3 | #### Privadas 4 | ``` 5 | ... 6 | ``` 7 | 8 | #### Compartidas 9 | ``` 10 | ... 11 | ``` 12 | 13 | ENLACES Y FUENTES 14 | ================= 15 | Buen resumen: 16 | https://atendesigngroup.com/blog/storing-session-data-drupal-8 17 | -------------------------------------------------------------------------------- /Back-end/Sqlite.md: -------------------------------------------------------------------------------- 1 | Sqlite 2 | ======== 3 | 4 | Comandos 5 | ``` 6 | // Acceder a la consila 7 | $ sqlite3 8 | $ drush sql:cli 9 | 10 | // Ayuda 11 | $ .help 12 | 13 | // Ver bases de datos 14 | $ .databases 15 | $ .dbinfo 16 | 17 | // Salir 18 | $ .exit 19 | ``` -------------------------------------------------------------------------------- /Back-end/Taxonomias.md: -------------------------------------------------------------------------------- 1 | Taxonomías 2 | ======== 3 | 4 | #### Trozos de código para obtener programaticamente. 5 | Optener el id de vocuabulario de un término 6 | ```php 7 | $vocabulary_id = $term->bundle(); 8 | ``` 9 | 10 | Obtener el arbol de términos de una taxonomía. 11 | ```php 12 | $tree = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree( 13 | 'id_vocabulario', 14 | 0, // id del termino padre(tid). "0" para obterner todos. 15 | 1, // Nivel del término. "1" Es es el primer nivel 16 | TRUE // Obtener la entidad del termino entera o un Stdclass. 17 | ); 18 | ``` 19 | 20 | Obtener todos los terminos padre de un término. 21 | ```php 22 | $ancestors = \Drupal::service('entity_type.manager')->getStorage("taxonomy_term")->loadAllParents($tid); 23 | $list = []; 24 | foreach ($ancestors as $term) { 25 | $list[$term->id()] = $term->label(); 26 | } 27 | ``` 28 | 29 | Obtener el padre directo de un término. 30 | ```php 31 | $parent = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadParents($termId); 32 | $parentEntity = reset($parent); 33 | $parent_term_id = array_key_first($parent) 34 | ``` 35 | 36 | 37 | ENLACES Y FUENTES 38 | ================= 39 | Términos y niveles. 40 | - https://boylesoftware.com/blog/drupal-8-get-taxonomy-terms-level/ 41 | -------------------------------------------------------------------------------- /Back-end/TempStorage.md: -------------------------------------------------------------------------------- 1 | TempStorage 2 | ======== 3 | 4 | #### Manejo 5 | 6 | ```php 7 | 8 | // Para poner valores en tempstorage 9 | $tempstore = \Drupal::service('tempstore.private'); 10 | $store = $tempstore->get('nombre_de_colección'); 11 | $store->set('key_name', $value); 12 | 13 | // Para recuperar los valores en tempstorage 14 | $tempstore = \Drupal::service('tempstore.private'); 15 | $store = $tempstore->get('nombre_de_colección'); 16 | $value = $store->get('key_name'); 17 | 18 | // Eliminar dato. De todas maneras el dato será removido en una semana. 19 | $store->delete('key_name'); 20 | ``` 21 | -------------------------------------------------------------------------------- /Back-end/Testeo.md: -------------------------------------------------------------------------------- 1 | TESTEO 2 | ======== 3 | 4 | #### 5 | 6 | 7 | ENLACES Y FUENTES 8 | ================= 9 | 10 | Test funcional 11 | - https://glamanate.com/blog/do-you-need-functional-test?utm_source=drupal-newsletter&utm_medium=email&utm_campaign=drupal-newsletter-20200910 -------------------------------------------------------------------------------- /Back-end/Tokens.md: -------------------------------------------------------------------------------- 1 | Tokens 2 | ======== 3 | 4 | #### Crear nuevos tokens 5 | En el archivo mi_modulo.tokens.inc 6 | ```php 7 | /** 8 | * @file 9 | * Contains functions related to tokens for Siblu. 10 | */ 11 | 12 | use Drupal\Core\Render\BubbleableMetadata; 13 | 14 | /** 15 | * Implements hook_token_info(). 16 | */ 17 | function mi_modulo_token_info() { 18 | $types['mi_modulo_product'] = [ 19 | 'name' => t('Product'), 20 | 'description' => t('Tokens related to current product.'), 21 | ]; 22 | 23 | $product = [ 24 | 'manager' => [ 25 | 'name' => t('Commerce product manager'), 26 | ], 27 | 'phone_number' => [ 28 | 'name' => t('Commerce product manager phone number'), 29 | ], 30 | ]; 31 | 32 | return [ 33 | 'types' => $types, 34 | 'tokens' => [ 35 | 'siblu_product' => $product, 36 | ], 37 | ]; 38 | } 39 | 40 | /** 41 | * Implements hook_tokens(). 42 | */ 43 | function mi_modulo_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) { 44 | $replacements = []; 45 | 46 | if ($type == 'mi_modulo_product') { 47 | $product = \Drupal::request()->attributes->get('commerce_product'); 48 | if (empty($product)) { 49 | return $replacements; 50 | } 51 | foreach ($tokens as $name => $original) { 52 | switch ($name) { 53 | case 'manager': 54 | case 'phone_number': 55 | if (!$product->{$name}->isEmpty()) { 56 | $replacements[$original] = $product->{$name}->value; 57 | } 58 | break; 59 | 60 | } 61 | } 62 | } 63 | 64 | return $replacements; 65 | 66 | } 67 | 68 | 69 | ``` 70 | 71 | -------------------------------------------------------------------------------- /Back-end/Usuarios.md: -------------------------------------------------------------------------------- 1 | Usuarios 2 | ======== 3 | #### Usuario actual 4 | ```php 5 | // Obtener usuario actual 6 | $user = \Drupal::currentUser(); 7 | // Verificar si el usuario tiene un permiso 8 | \Drupal::currentUser()->hasPermission("id_del_permiso") 9 | 10 | // Verificar si un usuario tiene un rol 11 | $current_user = \Drupal::currentUser(); 12 | $user = User::load($current_user->id()); 13 | $has_role = $user->hasRole('contributor'); 14 | ``` 15 | 16 | ### Usuario esta logueado 17 | ```php 18 | // Usuario actual está autentitcado 19 | $logged_in = \Drupal::currentUser()->isAuthenticated(); 20 | 21 | // Usuario actual es anónimo 22 | \Drupal::currentUser()->isAnonymous(); 23 | ``` 24 | 25 | #### Crear usuarios 26 | ```php 27 | $language = \Drupal::languageManager()->getCurrentLanguage()->getId(); 28 | $user = \Drupal\user\Entity\User::create(); 29 | 30 | // Configuraciones de campos clave 31 | $user->setPassword('clave'); 32 | $user->enforceIsNew(); 33 | $user->setEmail('email'); 34 | $user->setUsername('nombre_usuario'); 35 | 36 | // Configuraciones opcionales 37 | $user->set("init", 'email'); 38 | $user->set("langcode", $language); 39 | $user->set("preferred_langcode", $language); 40 | $user->set("preferred_admin_langcode", $language); 41 | 42 | $user->activate(); 43 | 44 | //Guardar usuario 45 | $res = $user->save(); 46 | ``` 47 | 48 | #### Loguear usuario 49 | ```php 50 | $account = user_load_by_name('nombre_usuario'); 51 | user_user_login($account); 52 | user_login_finalize($account); 53 | ``` 54 | 55 | #### Desloguear usuario 56 | ```php 57 | user_logout(); 58 | ``` 59 | 60 | #### Recuperar todos los usuarios y hacer consultas 61 | ```php 62 | $idsUsers = \Drupal::entityQuery('user')->execute(); 63 | $users = User::loadMultiple($idsUsers); 64 | foreach ($users as $user) { 65 | foreach ($user->get("roles") as $rol) { 66 | if ($rol->getValue()['target_id'] == "client_manager") { 67 | ... 68 | } 69 | } 70 | } 71 | ``` 72 | 73 | #### Recuperar un usuario 74 | ```php 75 | $user = User::load($idUser); 76 | 77 | ``` 78 | 79 | #### Cerrar sesión de un usuario 80 | ```php 81 | user_login_finalize($user); 82 | ``` 83 | 84 | #### Asignar privilegios a un rol 85 | ```php 86 | $role = \Drupal\user\Entity\Role::load('authenticated'); 87 | $role->grantPermission('access comments'); 88 | $role->save(); 89 | ``` 90 | 91 | #### Validar la contraseña de un usuario 92 | ```php 93 | $password = 'clave a validar'; 94 | $database = \Drupal::database(); 95 | $query = $database->query("SELECT pass FROM {users_field_data} WHERE uid = :uid;", [':uid' => $user->id()]); 96 | $current_password = $query->fetchAssoc()['pass']; 97 | $pass = $this->passwordHasher->check($password, $current_password); 98 | $result = 'failure'; 99 | if ($pass) { 100 | $result = 'success'; 101 | } 102 | ``` 103 | 104 | 105 | ENLACES Y FUENTES 106 | ================= 107 | Módulo User 108 | https://api.drupal.org/api/drupal/core!modules!user!user.module/8 109 | 110 | User.php 111 | https://api.drupal.org/api/drupal/core!modules!user!src!Entity!User.php/class/User/8 112 | 113 | Roles de usuario 114 | https://api.drupal.org/api/drupal/core!core.api.php/group/user_api/8 115 | -------------------------------------------------------------------------------- /Back-end/Variables.md: -------------------------------------------------------------------------------- 1 | Variables 2 | === 3 | 4 | #### Variables de estado 5 | ```php 6 | // Obtener un valor 7 | $value = \Drupal::state()->get('name_variable'); 8 | 9 | // Obtener un valor con valor por defecto en caso e no encontrar un valor. 10 | $value = \Drupal::state()->get('name_variable', valor_por_defecto); 11 | 12 | // Colocar un valor 13 | \Drupal::state()->set('name_variable', valor_variable); 14 | ``` 15 | 16 | -------------------------------------------------------------------------------- /Back-end/Vistas.md: -------------------------------------------------------------------------------- 1 | Vistas 2 | === 3 | 4 | Recuperar una vista la configuración de un display 5 | ```php 6 | use Drupal\views\Views; 7 | 8 | $view = Views::getView('gestion_des_formulaires'); 9 | $view->setDisplay('page_2'); 10 | $display = $view->getDisplay(); 11 | 12 | if (isset($display->options['filter_groups']['operator'])) { 13 | $operator = $display->options['filter_groups']['operator']; 14 | $filter_operators = $display->options['filter_groups']['groups']; 15 | foreach ($display->options['filters'] as $filter) { 16 | if ($filter['exposed']) { 17 | //... 18 | } 19 | } 20 | } 21 | ``` 22 | 23 | #### Filtros 24 | Crear un filtro expuesto mediante plugins 25 | - https://www.axelerant.com/resources/team-blog/creating-a-custom-exposed-view-filter-in-drupal-8-to-use-with-workflow-states 26 | Agregar - customizar elementos del formulario del plugin. 27 | - https://www.drupal.org/project/drupal/issues/2852299 28 | 29 | Crear un filtro expuesto mediante hooks 30 | - http://www.ermohitbansal.com/2019/08/31/how-we-can-create-custom-exposed-filter-in-views-and-fetch-results-accordingly-in-drupal-8/ 31 | 32 | Modificar filtro expuesto ajax mediante hook_form_alter + javascript 33 | - https://leanderlindahl.se/filter-content-in-a-drupal-8-view-with-ajax/ 34 | - http://www.softdecoder.com/blog/dynamically-filter-content-drupal-view 35 | 36 | #### Obtener datos 37 | Obtener los datos de una vista programaticamente 38 | - https://jbloomfield.codes/2018/09/24/drupal-8-getting-data-from-viewfield.html 39 | 40 | #### Manipular view 41 | Ejecutar una vista programaticamente 42 | - https://www.trivali.be/blog/drupal-8-execute-a-view-programmaticaly 43 | 44 | Customizar crear propio paginador 45 | - http://djevans.info/article/creating-views-pager-plugins-drupal-8 46 | - https://blog.werk21.de/en/2017/04/21/programmatically-change-views-pager-type-or-options 47 | 48 | Ejemplos de los principales hooks 49 | - https://drupalium.com/articles/insert-replace-delete-rows-from-view-results -------------------------------------------------------------------------------- /Back-end/Webform.md: -------------------------------------------------------------------------------- 1 | WEBFORM 2 | ======== 3 | 4 | 5 | #### 6 | Consultas 7 | ```php 8 | $submission_storage = \Drupal::entityTypeManager()->getStorage('webform_submission'); 9 | $ids_ws = $submission_storage->getQuery() 10 | ->accessCheck(FALSE) 11 | ->condition('uuid', $submission_uuid) 12 | ->execute(); 13 | if (count($ids_ws) == 1) { 14 | $id_ws = reset($ids_ws); 15 | $webform_submission = $submission_storage->load($id_ws); 16 | $webform_submission_data = $webform_submission->getData(); 17 | 18 | if ($webform_submission_data['numero_de_socio'] == $codigo_de_socio) { 19 | $email = $webform_submission_data['correo_electronico']; 20 | $whatsapp_number = $webform_submission_data['numero_celular_con_whatsapp']; 21 | $status = TRUE; 22 | } 23 | else { 24 | $status = FALSE; 25 | } 26 | } 27 | 28 | $select = \Drupal::service('database') 29 | ->select('webform_submission_data', 'wsd') 30 | ->fields('wsd', array('sid')) 31 | ->orderBy('wsd.sid', 'DESC') 32 | ->condition('wsd.webform_id', 'id_formulario', '=') 33 | ->condition('wsd.name', 'nombre_sistema_del_campo', '=') 34 | ->condition('wsd.value', $some_value, '=') 35 | ->execute(); 36 | $results = $select->fetchAll(\PDO::FETCH_COLUMN); 37 | 38 | ``` 39 | 40 | Actualización. 41 | ```php 42 | $submission_storage = \Drupal::entityTypeManager()->getStorage('webform_submission'); 43 | $ids = $submission_storage->getQuery() 44 | ->accessCheck(FALSE) 45 | ->condition('webform_id', 'id_del_webform') 46 | ->execute(); 47 | if (count($ids) > 0) { 48 | foreach ($ids as $id) { 49 | $submission = $submission_storage->load($id); 50 | $data = $submission->getData(); 51 | // Remove unused wich_session. 52 | if ($data['wich_formation'] != 'Bootcamp Ma Collection' && !empty($data['wich_session'])) { 53 | $submission->setElementData('wich_session', ''); 54 | $submission->save(); 55 | } 56 | } 57 | } 58 | ``` 59 | 60 | ENLACES Y FUENTES 61 | ================= 62 | 63 | Crear y actualizar envios de webform 64 | - https://www.drupal.org/docs/8/modules/webform/webform-cookbook/how-to-programmatically-create-and-update-a-submission -------------------------------------------------------------------------------- /Contribucion/README.md: -------------------------------------------------------------------------------- 1 | CONTRIBUIR 2 | ================= 3 | 4 | #### Parches que necesitan ser actualizados "Reroll" 5 | https://bit.ly/2QoEMyU 6 | 7 | #### Partes del código que se necesitan remplazar-deprecar "Kill includes" 8 | https://bit.ly/2Eiq8SL 9 | 10 | #### Herramientas útiles 11 | Para revizar que el código cumple los standares 12 | 13 | PHPlint https://www.drupal.org/node/2571965 14 | 15 | CSS lint https://www.drupal.org/node/1190252 16 | 17 | Coding standards https://www.drupal.org/node/1886770 18 | 19 | JS lint https://www.drupal.org/node/2490140 20 | 21 | Doc page https://www.drupal.org/node/1955232 22 | 23 | Buscar código en todos los proyectos contribuidos http://grep.xnddx.ru/ 24 | 25 | #### Referencias 26 | Cómo realizar re-roll 27 | https://www.drupal.org/patch/reroll 28 | 29 | Documentación etiquetas que pueden tener las issues 30 | https://www.drupal.org/issue-tags 31 | -------------------------------------------------------------------------------- /Contribucion/contribuir-modulo.md: -------------------------------------------------------------------------------- 1 | Crear un módulo y contribuirlo 2 | ======== 3 | 4 | Crear el proyecto en drupal.org 5 | 1. Ir a https://www.drupal.org/project/user 6 | 2. Crear en el link "Add a new project" 7 | 8 | Subir el código al repositorio oficial de drupal 9 | ```bash 10 | mkdir total_visitor_counter 11 | cd total_visitor_counter 12 | git init 13 | git checkout -b 1.0.x 14 | echo "Total visitor counter" > README.txt 15 | git add README.txt 16 | git commit -m "Initial commit." 17 | git remote add origin git@git.drupal.org:project/total_visitor_counter.git 18 | git push origin 1.0.x 19 | ``` 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Contribucion/corregir-parche.md: -------------------------------------------------------------------------------- 1 | Resolver problemas en un parche 2 | ======== 3 | ``` 4 | Se trata de resolver problemas de testeo, problemas detectados y/o comentados. 5 | ``` 6 | 7 | 8 | #### Pasos previos 9 | ``` 10 | 1. Identificar una issue con la estado "Needs work" 11 | https://www.drupal.org/project/issues/search/drupal?status%5B%5D=13&version%5B%5D=8.x 12 | 13 | 2. Encontrar una issue en la que se sienta capaz que se puede resolver los problemas en el parche subido. 14 | 15 | 3. Actualizar el core 16 | $ git checkout 8.7.x 17 | $ git pull --rebase 18 | 19 | 4. Descargar el parche en el comentario más reciente 20 | ``` 21 | 22 | #### Resolver los problemas 23 | ``` 24 | 1. Ir a la issue y copiar la fecha en el comentario del parche descargado 25 | 26 | 2. Ver el log de commits de esa fecha 27 | $ git log --before="12 November 2018 at 12:15" 28 | 29 | 3. Tomar los primeros 9 caracteres del código del primer commit e ir a este 30 | $ git checkout -b test-branch 749f569c6 31 | 32 | 4. Aplicar el parche 33 | $ git apply --index 2599228-93.patch 34 | 35 | 5. Commit del parche 36 | $ git commit -m "Applying patch from issue 2599228 comment 12852422" 37 | 38 | 6. Intenta hace pull de todos los cambios que han sido hechos desde el commit del parche. 39 | $ git rebase 8.7.x 40 | 41 | Si hay conflictos: Realizar los conflictos del rebase. 42 | https://www.drupal.org/node/2723783 43 | 44 | Si no hay conflictos 45 | - RESOLVER LOS PROBLEMAS EN EL PARCHE 46 | $ git add -p 47 | $ git commit -m "Solving problem at patch from issue 2599228 comment 12852422" 48 | - Crear un parche con un diff de tu branch local (test-branch) sobre la rama principal: 49 | $ git diff -M 8.7.x test-branch > numero_issue-numero_comentario.patch 50 | Verificar si el parche creado es correcto 51 | $ git checkout 8.7.x 52 | $ git apply --check numero_issue-numero_comentario.patch 53 | (no output) 54 | Crear un interdiff 55 | $ interdiff viejo.patch nuevo.patch > interdiff_[numero_comentario_viejo]-[numero_comentario_nuevo].txt 56 | ``` 57 | #### Referencias 58 | ``` 59 | Interdiff 60 | https://www.drupal.org/documentation/git/interdiff 61 | ``` 62 | -------------------------------------------------------------------------------- /Contribucion/crear-un-parche.md: -------------------------------------------------------------------------------- 1 | Crear un parche 2 | ======== 3 | ``` 4 | Se trata de resolver problemas en una issue de drupal y crear un parche. 5 | ``` 6 | 7 | ``` 8 | Clonar el repositorio del proyecto con la issue: 9 | De https://www.drupal.org/project/lightning_workflow/git-instructions copiar: 10 | $ git clone --branch 8.x-3.x https://git.drupalcode.org/project/lightning_workflow.git 11 | $ cd lightning_workflow 12 | $ git checkout -b nombre_rama_nueva 13 | 14 | Modificar el código del módulo resolviendo el issue en cuestión. 15 | ... 16 | 17 | Crear el parche con la sulución: 18 | $ git add -p 19 | $ git commit -m "...." 20 | $ git diff -M 8.x-3.x nombre_rama_nueva > numero_issue-numero_comentario.patch 21 | 22 | Verificar si el parche creado es correcto 23 | $ git checkout 8.x-3.x 24 | $ git apply --check numero_issue-numero_comentario.patch 25 | (no output) 26 | 27 | Aplicar el parche para verificar el correcto funcionamiento 28 | $ git checkout 8.x-3.x 29 | $ git apply --index numero_issue-numero_comentario.patch 30 | -------------------------------------------------------------------------------- /Contribucion/entorno.md: -------------------------------------------------------------------------------- 1 | Entorno 2 | ======== 3 | #### Docker con mysql, apache, tests unitarios en DOCKSAL 4 | ``` 5 | Para drupal 8 6 | https://github.com/docksal/drupal8-contrib 7 | 8 | Clonar el repositorio 9 | $ git clone git@github.com:docksal/drupal8-contrib.git drupal8 10 | 11 | Para drupal 9 12 | https://github.com/docksal/drupal9-contrib 13 | Clonar el repositorio 14 | $ git clone git@github.com:docksal/drupal9-contrib.git 15 | 16 | 17 | Levantar el entorno 18 | $ cd >carpeta> 19 | $ fin init 20 | 21 | Ejecutar tests unitarios 22 | $ fin bash 23 | $ cd docroot 24 | $ vendor/bin/phpunit -c core modules/contrib/domain/domain/tests/src/Functional/Views/ActiveDomainDefaultArgumentTest.php 25 | 26 | ``` 27 | 28 | #### Docker con sqlite + correr tests unitarios 29 | ``` 30 | Descargar el core de drupal 31 | https://www.drupal.org/project/drupal/git-instructions 32 | 33 | Descargar Makefile para correr un docker de drupal sobre sqlite 34 | https://gist.github.com/andypost/f8e359f2e80cb7d4737350189f009646#file-makefile 35 | 36 | Ejecutar composer 37 | $ composer install 38 | 39 | Ejecutar ambiente docker 40 | $ make -s up 41 | Revisar en: http://localhost:8080/ 42 | 43 | Ejecutar los tests de un módulo. Ejemplo Taxonomy 44 | $ make t t=core/modules/taxonomy/tests/src/Unit/Menu/TaxonomyLocalTasksTest.php 45 | ``` 46 | #### Entorno local + correr tests unitarios + verificación estándares del código 47 | ``` 48 | Descargar el core de drupal y colocar en una carpeta local que levante un host normal como sueles hacerlo en tu entorno. 49 | https://www.drupal.org/project/drupal/git-instructions 50 | 51 | Entrar en la carpeta de drupa y ejecutar composer 52 | $ composer install 53 | 54 | Instalar drupal (puede ser desde el navegador) 55 | 56 | ENTORNO PARA TESTGS UNITARIOS 57 | Activar entorno para ejecutar tests unitarios 58 | $ mkdir sites/default/simpletest 59 | $ chmod 777 -R sites/default/simpletest 60 | $ cp core/phpunit.xml.dist core/phpunit.xml 61 | 62 | Configurar el archivo phpunit.xml modificando las variables de entorno 63 | 64 | 65 | 66 | Ejecutar los tests: Ejemplo 67 | vendor/bin/phpunit --configuration core core/tests/Drupal/KernelTests/Core/Bootstrap/GetFilenameTest.php 68 | 69 | ENTORNO PARA VERIFICACIÓN DE ESTÁNDARES DEL CÓDIGO 70 | $ composer global require drupal/coder 71 | $ set PATH $PATH $HOME/.config/composer/vendor/bin 72 | $ phpcs --config-set installed_paths ~/.config/composer/vendor/drupal/coder/coder_sniffer 73 | $ phpcs -i 74 | Debe mostrar "The installed coding standards are Zend, PSR12, PSR1, Squiz, PSR2, MySource, PEAR, DrupalPractice and Drupal" 75 | $ phpcs --standard=Drupal /ruta_a_carpeta_o_archivo/ 76 | ``` 77 | ENLACES Y FUENTES 78 | ================= 79 | Ejecutar tests unitarios 80 | - https://www.drupal.org/docs/8/phpunit/running-phpunit-tests 81 | 82 | Estándares del código 83 | - https://www.drupal.org/node/1419988 84 | 85 | Trabajar con git y gitlab 86 | - https://www.drupal.org/docs/develop/git/using-git-to-contribute-to-drupal/creating-issue-forks-and-merge-requests?utm_source=Drupal+Project+Maintainers&utm_campaign=ed227e9b0b-EMAIL_CAMPAIGN_2020_09_10_08_14_COPY_03&utm_medium=email&utm_term=0_42888f3d61-ed227e9b0b-298566141 87 | -------------------------------------------------------------------------------- /Contribucion/gitlab.md: -------------------------------------------------------------------------------- 1 | Contribuir gitlab 2 | ======== 3 | 4 | - Ejemplo issue que contribuye mediante gitlab 5 | https://www.drupal.org/project/simple_popup_blocks/issues/3211543 6 | 7 | - Cómo cobtribuir mediante gitlab 8 | https://www.drupal.org/docs/develop/git/using-git-to-contribute-to-drupal/creating-issue-forks-and-merge-requests -------------------------------------------------------------------------------- /Contribucion/merge-request.md: -------------------------------------------------------------------------------- 1 | Merge Request (Gitlab) 2 | ======== 3 | 4 | Guía en video: 5 | 6 | https://www.youtube.com/watch?v=NIWCXE-aM6Y&utm_source=Drupal+Project+Maintainers&utm_campaign=99c7712471-EMAIL_CAMPAIGN_2020_12_01_05_33&utm_medium=email&utm_term=0_42888f3d61-99c7712471-298566141 -------------------------------------------------------------------------------- /Contribucion/reroll.md: -------------------------------------------------------------------------------- 1 | Actualización de parches (Reroll) 2 | ======== 3 | 4 | ``` 5 | Se trata de actualizar soluciones que han quedado incompatibles con cambios recientes en el código. 6 | ``` 7 | 8 | #### Pasos previos 9 | ``` 10 | 1. Filtrar issues que tienen necesidad de Reroll. Escoger una. 11 | https://www.drupal.org/project/issues/search/drupal?issue_tags=Needs+reroll 12 | 13 | 2. Confirmar que el parche necesita reroll 14 | 15 | Actualizar el core 16 | $ git checkout 8.8.x 17 | $ git pull --rebase 18 | 19 | Descargar el parche 20 | 21 | Verficiar el parche 22 | $ git apply --check nombre-archivo.patch 23 | Si el resultado es vacio el parche no necesita ser actualizado. 24 | - Quitar el tag: "Needs reroll" 25 | - Dejar un comentario "I could apply the patch, so no reroll is needed." 26 | Si el resultado es que se necesita el reroll: 27 | Dejar un comentario avisando que se está empezando a hacer el reroll y asignarse la tarea mientras dure el trabajo. 28 | ``` 29 | 30 | #### Actualización de parches (Reroll) 31 | ``` 32 | 1. Ir a la issue y copiar la fecha en el comentario del parche descargado 33 | 34 | 2. Ver el log de commits de esa fecha 35 | $ git log --before="12 November 2018 at 12:15" 36 | 37 | 3. Tomar los primeros 9 caracteres del código del primer commit e ir a este 38 | $ git checkout -b test-branch 749f569c6 39 | 40 | 4. Aplicar el parche 41 | $ git apply --index 2599228-93.patch 42 | 43 | 5. Commit del parche 44 | $ git commit -m "Applying patch from issue 2599228 comment 12852422" 45 | 46 | 6. Intenta hace pull de todos los cambios que han sido hechos desde el commit del parche. 47 | $ git rebase 8.8.x 48 | 49 | Si hay conflictos: Resolver los conflictos del rebase. 50 | https://www.drupal.org/node/2723783 51 | 52 | Si no hay conflictoss 53 | - Crear un parche con un diff de tu branch local (test-branch) sobre la rama principal: 54 | $ git diff -M 8.7.x test-branch > breve_descripción-nro_caso-nro_comentario.patch 55 | Verificar si el parche creado es correcto 56 | $ git checkout 8.7.x 57 | $ git apply --check breve_descripción-nro_caso-nro_comentario.patch 58 | (no output) 59 | ``` 60 | 61 | ENLACES Y FUENTES 62 | ================= 63 | Reroll 64 | https://www.drupal.org/contributor-tasks/reroll 65 | -------------------------------------------------------------------------------- /Contribucion/utilidades.md: -------------------------------------------------------------------------------- 1 | Utilidades para contribuir 2 | ======== 3 | 4 | Buscar dentro del código de todos los proyectos contribuidos a drupal 5 | - http://grep.xnddx.ru/ 6 | -------------------------------------------------------------------------------- /DevOps/IDEs/Atom.md: -------------------------------------------------------------------------------- 1 | ATOM 2 | === 3 | ``` 4 | ¿Porque atomon? 5 | - ATOM presenta infinita libertad debido a que es un editor libre de codigo abierto. 6 | - Existen muchos paquetes disponibles que hacen que no se tenga nada que envidiar a editores como PHPStorm, Sublime, Eclipse. 7 | ``` 8 | INSTALACIÓN 9 | == 10 | ``` 11 | $ curl -L https://packagecloud.io/AtomEditor/atom/gpgkey | sudo apt-key add - 12 | $ sudo sh -c 'echo "deb [arch=amd64] https://packagecloud.io/AtomEditor/atom/any/ any main" > /etc/apt/sources.list.d/atom.list' 13 | $ sudo apt-get update 14 | $ sudo apt-get install atom 15 | ``` 16 | 17 | PAQUETES RECOMENDADOS 18 | == 19 | ``` 20 | Autocompletar código php que tiene dependencias composer 21 | atom-autocomplete-php 22 | 23 | Ir a la definición de una variable, clase o función 24 | goto-definition 25 | 26 | Hacer ctrl+click en un texto y te envia a su definición (ctrl+shift desde teclado) 27 | hyperclick 28 | js-hyperclick 29 | php-hyperclick 30 | ``` 31 | 32 | REFERENCIAS 33 | == 34 | ``` 35 | https://atom.io 36 | ``` 37 | -------------------------------------------------------------------------------- /DevOps/IDEs/visualstudiocode.md: -------------------------------------------------------------------------------- 1 | VISUAL STUDIO CODE 2 | === 3 | ``` 4 | ¿Porque Visual Studio Code? 5 | Es ligero y presenta todas las funcionalidades que a un programador le ahorran tiempo y esfuerzo: 6 | - Autocompleta código: php, js, html, css 7 | - Reconoce el formato del código: php, js, html, css, twig, htaccess 8 | - Soporta snipets. 9 | - Marca el versionamiento del código git. 10 | - Con ctrl-click se dirige directamente al código que implementa una funcionalidad. 11 | - Cuando se escribe código autocompleta las librerías que lo contienen PHP-Drupal 12 | ``` 13 | 14 | INSTALACIÓN 15 | == 16 | ``` 17 | Desgargar .deb de https://code.visualstudio.com/ 18 | $ sudo dpkg -i code_1.26.1-1534444688_amd64.deb 19 | ``` 20 | 21 | PAQUETES RECOMENDADOS 22 | == 23 | ``` 24 | PHP: 25 | PHP Intelephense: Autocompletar y refactorizar código (promete ser el más veloz y completo!) 26 | PHP debug: Debuguear con XDebug 27 | 28 | TWIG 29 | Twig Language: Sintaxis, snippets, autocompletado de twig y html 30 | 31 | HTML CSS 32 | Html Snipets: Autocompletado de código html incluido html 5 33 | Html Css Support: Autocompletado de clases, ids, archivos remotos. 34 | 35 | DRUPAL 36 | Drupal 8 Twig Snippets: Las funciones más comunes para enlazar drupal-twig 37 | Drupal 8 Snippets: Los hooks 38 | Drupal 8 Javascript Snippets: Las funciones más comunes para enlazar drupal-js 39 | 40 | GIT 41 | Git History: Ver el log, historial de un archivo, comparar ramas y commits 42 | 43 | JS 44 | (¿Que recomiendas?) 45 | 46 | DOCKER 47 | Docker (Microsoft): Sintaxis, comandos y tip (on hover) para archivos dockerfile y docker-compose 48 | 49 | ``` 50 | 51 | REFERENCIAS 52 | == 53 | ``` 54 | Página oficial 55 | https://code.visualstudio.com/ 56 | 57 | Utilización con Drupal 58 | https://www.drupal.org/docs/develop/development-tools/configuring-visual-studio-code 59 | 60 | Recomendaciónes para trabajar con php 61 | https://code.visualstudio.com/docs/languages/php 62 | 63 | ``` 64 | -------------------------------------------------------------------------------- /DevOps/Seguridad.md: -------------------------------------------------------------------------------- 1 | Seguridad 2 | === 3 | 4 | ### Configuración de permisos 5 | ``` 6 | Permisos 7 | sites -> 755 8 | sites/default -> 755 9 | sites/default/files -> 775 10 | sites/default/settings.php -> 444 11 | sites/default/services.yml -> 444 12 | ``` 13 | -------------------------------------------------------------------------------- /DevOps/composer.md: -------------------------------------------------------------------------------- 1 | COMPOSER 2 | ======== 3 | 4 | #### Instalar Composer globalmente (pre-requisito) 5 | ```bash 6 | curl -sS https://getcomposer.org/installer | php 7 | sudo mv composer.phar /usr/local/bin/composer 8 | # Para fedora, aws EC2 9 | ln -s /usr/local/bin/composer /usr/bin/composer 10 | 11 | #Evitar el corte por tiempo de espera excesivo 12 | "config": { 13 | "process-timeout": 0, 14 | }, 15 | ``` 16 | 17 | 18 | ENLACES Y FUENTES 19 | ================= 20 | Composer y drupal 21 | - https://www.amazeelabs.com/en/drupal-composer-recipes 22 | 23 | Buenas prácticas composer 24 | - https://www.lullabot.com/articles/drupal-8-composer-best-practices 25 | 26 | Template composer 27 | - https://github.com/drupal-composer/drupal-project 28 | -------------------------------------------------------------------------------- /DevOps/docker.md: -------------------------------------------------------------------------------- 1 | DOCKER 2 | ======== 3 | #### Instalar docker en ubuntu 18.04 4 | ```bash 5 | # Desinstalar versiones antiguas de docker 6 | $ sudo apt-get -y remove docker docker-engine docker.io 7 | $ sudo apt-get update 8 | 9 | # Instalar paquetes necesarios para la instalación 10 | $ sudo apt-get install -y apt-transport-https software-properties-common ca-certificates curl wget 11 | 12 | # Agregar clave GPG para el repositorio de Docker 13 | $ wget https://download.docker.com/linux/ubuntu/gpg 14 | $ sudo apt-key add gpg 15 | $ sudo apt-get update 16 | 17 | # Agregar el repositorio docker a las fuentes APT 18 | $ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" 19 | 20 | # Actualizar la base de datos de paquetes 21 | $ sudo apt-get update 22 | 23 | # Asegurarse de que se va instalar docker del repositorio oficial y no del por defecto de ubuntu 24 | $ apt-cache policy docker-ce 25 | #Esto desplegará algo como esto: 26 | Output of apt-cache policy docker-ce 27 | docker-ce: 28 | Installed: (none) 29 | Candidate: 18.03.1~ce~3-0~ubuntu 30 | Version table: 31 | 18.03.1~ce~3-0~ubuntu 500 32 | 500 https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages 33 | Note que docker-ce no está instalado y toma como candidato una versión de repositorio oficial para Ubuntu 18.04 (bionic). 34 | 35 | # Instalar Docker 36 | $ sudo apt-get -y install docker-ce 37 | 38 | # Verificar la instalación de docker 39 | $ sudo systemctl status docker 40 | 41 | # Decirle al sistema que arranque siempre con docker 42 | $ sudo systemctl start docker 43 | $ sudo systemctl enable docker 44 | 45 | # Verificar que docker funciona correctamente 46 | $ sudo docker run hello-world 47 | 48 | # Opcional: Agregar usuario al grupo docker para evitar esribir sudo todo el tiempo 49 | $ sudo usermod -aG docker 50 | # Aplicar la membresía al grupo 51 | $ su - 52 | # Confirmar que el usuario se encuentra en el grupo de docker 53 | $ id -nG 54 | 55 | # Instalar docker-compose 56 | # Desactivar fish 57 | $ bash 58 | # Instalar 59 | $ sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose 60 | $ sudo chmod +x /usr/local/bin/docker-compose 61 | #Revisar si se encuentra bien instalado 62 | $ docker-compose --version 63 | ``` 64 | 65 | 66 | #### Instalar docker en ubuntu 16.04 67 | ```bash 68 | Crear una cuenta de usuario que no sea root, con privilegios de sudo 69 | $ adduser docker 70 | $ usermod -aG sudo docker 71 | 72 | Actualizar la base de datos de paquetes 73 | $ sudo apt-get update 74 | 75 | Agregar la clave GPG para el repositorio oficial de Docker al sistema 76 | $ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D 77 | 78 | Agregar el repositorio Docker a fuentes APT 79 | $ sudo apt-add-repository 'deb https://apt.dockerproject.org/repo ubuntu-xenial main' 80 | 81 | Actualizar la base de datos de paquetes 82 | $ sudo apt-get update 83 | 84 | Verificar que está a punto de instalar desde el repositorio de Docker en lugar del repositorio predeterminado de Ubuntu 85 | $ apt-cache policy docker-engine 86 | 87 | Instalar Docker 88 | $ sudo apt-get install -y docker-engine 89 | 90 | Comprobar que docker se está ejecutando 91 | $ sudo systemctl status docker 92 | 93 | Opcional: Agregar usuario al grupo docker para evitar esribir sudo todo el tiempo 94 | $ sudo usermod -aG docker 95 | 96 | Instalar Docker compose 97 | $ sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 98 | $ sudo chmod +x /usr/local/bin/docker-compose 99 | Verificar versión instalada 100 | $ docker-compose --version 101 | 102 | Instalar comando make 103 | $ sudo apt-get install make 104 | ``` 105 | 106 | #### Montar drupal y ejecutarlo 107 | ```bash 108 | Bajar contenedor oficial de drupal () 109 | $ docker pull drupal 110 | 111 | Ejecutar drupal con base de datos SQLite 112 | $ docker run --name some-drupal -p 8080:80 -d drupal 113 | 114 | Ver en el navegador esta instancia: 115 | http://localhost:8080 116 | 117 | ``` 118 | 119 | 120 | 121 | ENLACES Y FUENTES 122 | ================= 123 | Instalar docker en ubuntu 16.04 124 | https://www.digitalocean.com/community/tutorials/como-instalar-y-usar-docker-en-ubuntu-16-04-es 125 | 126 | Instalar docker en ubuntu 18.04 127 | https://www.itzgeek.com/how-tos/linux/ubuntu-how-tos/how-to-install-docker-on-ubuntu-18-04-lts-bionic-beaver.html 128 | https://linuxconfig.org/how-to-install-docker-on-ubuntu-18-04-bionic-beaver 129 | 130 | Contenedor oficial de drupal 131 | https://hub.docker.com/_/drupal/ 132 | 133 | Comandos de docker 134 | https://docs.docker.com/engine/reference/commandline/docker/ 135 | 136 | Entorno drupal con las herramientas más útiles 137 | https://cloud.wodby.com/stackhub/ada51e9b-2204-45ee-8e49-a4151912a168/overview 138 | 139 | Montar docker en windows wsl 140 | https://dev.to/felipecrs/simply-run-docker-on-wsl2-3o8 -------------------------------------------------------------------------------- /DevOps/drush.md: -------------------------------------------------------------------------------- 1 | DRUSH 2 | ======== 3 | 4 | #### Instalar 5 | ```bash 6 | # Visitar https://github.com/drush-ops/drush/releases y descargar drush.phar (8.x recomendado). 7 | 8 | # Verificar archivo. 9 | php drush.phar core-status 10 | 11 | # Renombrar `drush` por `php drush.phar`. y mover archivo $PATH. 12 | chmod +x drush.phar 13 | sudo mv drush.phar /usr/local/bin/drush 14 | 15 | # Opcional. Habilita alias 16 | drush init 17 | ``` 18 | 19 | #### Comandos más útiles 20 | ```bash 21 | # Ver log de errores 22 | drush watchdog-show 23 | 24 | # Actualizar un proyecto drupal: saca backup, actualiza el código y actualiza la base de datos 25 | drush up 26 | 27 | # Lista de módulos activos que no son del core. 28 | drush pm-list --type=Module --no-core --status=enabled 29 | 30 | # Cambiar la contraseña de un usuario 31 | drush user-password USERNAME --password="SOMEPASSWORD" 32 | 33 | # Reconstruir rutas 34 | drush ev '\Drupal::service("router.builder")->rebuild();' 35 | 36 | # loguear como admin 37 | drush uli --uri local.misitio.com 38 | 39 | # Ver todos los servicios 40 | drush devel-container-services 41 | 42 | # verificar una configuración activa 43 | drush cget nombre_configuracion 44 | 45 | # Manejar hook_update 46 | drush php-eval "echo drupal_get_installed_schema_version('siblu_field');" 47 | drush php-eval "echo drupal_set_installed_schema_version('siblu_field', '8004');" 48 | drush updb -y 49 | 50 | # Deploy 51 | drush deploy 52 | 53 | Drush deploy ejecuta: 54 | drush updatedb --no-cache-clear 55 | drush cache:rebuild 56 | drush config:import 57 | drush cache:rebuild 58 | drush deploy:hook 59 | 60 | # Search API 61 | drush search-api:rebuild-tracker && drush search-api:index 62 | drush crons 63 | 64 | ``` 65 | # Comandos base de datos 66 | ```bash 67 | # actualizar base de datos 68 | drush updb -y 69 | 70 | # Entrar modo consola a la base de datos 71 | $ drush sql-cli 72 | 73 | # Sacar backup de la base de datos. 74 | $ drush sql-dump 75 | $ drush sql-dump > default.sql 76 | 77 | # importar contenido por defecto 78 | drush default-content:import-all 79 | ``` 80 | 81 | # Comandos usuarios 82 | ```bash 83 | # Crear usuario 84 | drush user-create 85 | 86 | # Cambiar de clave usuario 87 | drush user-password 88 | 89 | # Agregar rol a usuario 90 | drush user-add-role 91 | 92 | # Bloquear un usuario 93 | drush user-block 94 | 95 | # Desbloquear un usuario 96 | drush user-unblock 97 | 98 | # Desloguear todos los usuarios 99 | drush sql-query 'TRUNCATE TABLE sessions;' 100 | 101 | # Desloguear un usuario en específico 102 | drush sql-query 'DELETE FROM sessions WHERE uid = 2;' 103 | ``` 104 | 105 | # Comandos para manipular configuraciones 106 | ```bash 107 | # Editar configuración activa 108 | drush config-edit 109 | 110 | # importar configuraciones 111 | drush cim -y 112 | 113 | # exportar configuraciones 114 | drush cex 115 | ``` 116 | 117 | # Comandos gestion del sitio 118 | ```bash 119 | # Sitio en modo mantenimiento 120 | drush state:set system.maintenance_mode 1 --input-format=integer 121 | drush state:set system.maintenance_mode 0 --input-format=integer 122 | ``` 123 | 124 | #### REFERENCIAS 125 | ``` 126 | Comandos más utilizados 127 | - https://orga.cat/posts/most-useful-drush-commands 128 | 129 | Instalar drush 8 (Drupal 8 + Drupal 7) 130 | - wget http://files.drush.org/drush.phar 131 | 132 | Comandos base de datos 133 | - https://drushcommands.com/drush-8x/sql/ 134 | ``` 135 | -------------------------------------------------------------------------------- /DevOps/git.md: -------------------------------------------------------------------------------- 1 | GIT 2 | === 3 | ```bash 4 | # Instalación en sistemas debian, ubuntu 5 | sudo apt-get install git 6 | 7 | # Configuración de usuario 8 | git config --global user.name usuario 9 | git config --global user.email usuario@correo.com 10 | git config --global core.editor emacs 11 | git config --list 12 | 13 | # Configuración estilo de fin de línea para linux-mac: Auto modifica CTRL (Windows) a LF (Unix) 14 | git config --global core.autocrlf input 15 | 16 | # Generar las llaves pública y privada 17 | ssh-keygen -t rsa -C usuario@correo.com 18 | 19 | # Ignorar archivos o carpetas para el versionamiento 20 | # 1. Crear un archivo .gitignore en la rais de la carpeta versionada 21 | # 2. Escribir en el archivo .gitignore los archivos y carpetas a ignorar. Por ejemplo 22 | # .idea/ 23 | # .gitignore 24 | 25 | # Perder todos los cambios que no fueron commiteados 26 | git checkout -f 27 | 28 | # Crear una rama o branch nueva 29 | git branch crazy-experiment 30 | git checkout crazy-experiment 31 | #... codificar cambios ... 32 | git add -A 33 | git commit -m "message..." 34 | git push origin crazy-experiment 35 | 36 | # Agregar y Quitar archivos (Equivalente git add, git rm juntos) 37 | git add -u 38 | 39 | # Añadir porciones de cambios dentro de cada archivo al stage de cambios 40 | git add -p 41 | 42 | # Quitar archivos 43 | git rm 44 | 45 | # Cambiar de nombre una rama 46 | git branch -m 47 | # Si estas en la rama que deseas cambiar de nombre 48 | git branch -m 49 | 50 | # Deshacer cambios del pull mas reciente 51 | git reset --hard 52 | 53 | # Retrocedemos al último commit y perdemos todos los cambios hechos. 54 | git reset --hard HEAD~1 55 | 56 | # Retrocedemos a el último commit y no perdemos los cambiosn hechos; apareceran pendientes de hace commit 57 | git reset --soft HEAD~1 58 | 59 | # Cancelar commit (antes de hacer push) 60 | git reset --hard HEAD~1 61 | 62 | # Reponer archivo eliminado que no ha sido comiteado 63 | git checkout HEAD 64 | 65 | # Ver cambios de un commit 66 | git show 67 | 68 | # Visualizar una rama existente 69 | git checkout crazy-experiment 70 | 71 | # Ver el historial gráficamente 72 | git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s" 73 | 74 | # Ver el historial de un archivo 75 | git log /ruta/archivo 76 | 77 | # Ver el historial de un usuario 78 | git log --author="vacho" 79 | 80 | # Ver el historia de cada línea de codigo de un archivo 81 | git blame /ruta/archivo 82 | 83 | # Ver el historial de un trozo de código 84 | git log --all -p -STrozo_de_codigo 85 | 86 | # Mezclar una rama con el master 87 | git checkout master 88 | git merge crazy-experimient 89 | 90 | # Agregamos una rama delante del master 91 | git checkout master 92 | git rebase crazy-experimient 93 | 94 | # Eliminar un branch 95 | git branch -D crazy-experiment 96 | git push origin :crazy-experiment 97 | 98 | # Ver aportes de líneas a un archivo 99 | git blame /ruta/archivo 100 | 101 | # Ver cambios en un archivo 102 | git diff /ruta/archivo 103 | 104 | # Ver cambios entre 2 commits 105 | git diff --name-only SHA1 SHA2 106 | 107 | # Arreglar el último commit en lugar de un nuevo commit 108 | # editamos hola.py y main.py 109 | git add hola.py 110 | git commit 111 | # añadir los cambios de main.py en el último commit 112 | git add main.py 113 | git commit --amend --no-edit 114 | 115 | # Hacer merge de un específico commit de una rama en otra rama (donde se esta trábajando) 116 | git cherry-pick 117 | 118 | # Lista de los commits que tienen un texto 119 | git log --all --grep='' 120 | 121 | # Restaurar un archivo borrado que no ha sido commiteado 122 | # Restaura el estado del archivo en index 123 | git reset -- 124 | # Salida del cambio hecho en el archivo en index 125 | git checkout -- 126 | 127 | #Ignorar un archivo en el repositorio sin .gitignore 128 | git update-index --skip-worktree /sites/default/settings.php 129 | 130 | ``` 131 | 132 | Trabajar como fork de un repositorio y actualizar 133 | === 134 | ```bash 135 | # Mostrar repositorios remotos 136 | git remote -v 137 | 138 | # Eliminar repositorios 139 | git remote rm 140 | 141 | # Añadir repositorio remoto, llamarlo "upstream": 142 | git remote add upstream https://github.com/whoever/whatever.git 143 | 144 | # Añadir repositorio remoto, para usarlo en repo github 145 | git remote add origin git@github.com:usuario_github/nombre_mi_proyecto.git 146 | 147 | # Extraer todos los branchs 148 | git fetch upstream 149 | 150 | # Estar seguro de que se está en el branch master 151 | git checkout master 152 | 153 | # Reescribir todos los commits 154 | git rebase upstream/master 155 | 156 | # Juntar 2 o más commits en uno. N viene a ser el número de commits que deseas juntar. 157 | git rebase --interactive HEAD~N 158 | # Luego en la edición tienes que cambiar por en cada línea de commit que deseas juntar. 159 | 160 | ``` 161 | 162 | Montar repositorio para trabajar en remoto 163 | === 164 | ```bash 165 | # En la carpeta a versionar: 166 | git init 167 | 168 | # habilitamos la posibilidad de hacer push 169 | $ git config receive.denyCurrentBranch ignore 170 | 171 | # Git manejará los finales de línea linux-windows 172 | git config --global core.autocrlf true 173 | git config --global core.whitespace cr-at-eol 174 | 175 | git add . 176 | git commit -m "inicio" 177 | git checkout -f 178 | 179 | # Evitar hacer git checkout -f todo el tiempo 180 | cd .git/hooks 181 | vim post-receive 182 | # Colocar las siguientes 2 líneas 183 | #!/bin/sh 184 | GIT_WORK_TREE=../ git checkout -f 185 | chmod +x post-receive 186 | 187 | # Para clonar 188 | git clone ssh://nombre_cuenta@ip_servidor:puerto/ruta_a_la_carpeta 189 | 190 | ``` 191 | Ignorar archivos de un repositorio 192 | === 193 | ```bash 194 | # Crear un .gitignore con la ruta relativa a las carpetas o archivos a omitir 195 | git rm -r --cached . 196 | git add . 197 | git commit -m "reiciniamos git" 198 | ``` 199 | 200 | Ver reportes gráficos del repositorio. 201 | === 202 | ```bash 203 | # ver el historial de cambios de un archivo 204 | gitk nombre_archivo.extension 205 | ``` 206 | 207 | Deshacer cambios como rebases. 208 | === 209 | ```bash 210 | git reflog 211 | # Supongamos que el commit más viejo es HEAD@{5} en el log log: 212 | git reset --hard "HEAD@{5}" 213 | ``` 214 | Juntar los 2 commits finales en uno mismo. 215 | === 216 | ```bash 217 | # Si estas en el commit_1 y quieres mergear el commit_2" en el commit_1. 218 | git rebase -i HEAD~2 219 | # Lo cual muestra en el editor la lista de todos los commits para hacer rebase. 220 | # Veras 2 líneas que comienzan con "pick". 221 | # Cambiar la primera palabra de la segunda línea de "pick" a "squash". 222 | # Guardar el archivo. 223 | ``` 224 | 225 | Revisar el log de commits. 226 | === 227 | ```bash 228 | # ver el historial de cambios. 229 | git log 230 | 231 | # ver sólo los archivos modificados. 232 | git diff-tree --no-commit-id --name-only -r 233 | 234 | # Ver el detalle de los cambios en un archivo. 235 | git show 236 | ``` 237 | 238 | Omitir archivo previamente agregado. 239 | === 240 | ```bash 241 | echo debug.log >> .gitignore 242 | git rm --cached debug.log 243 | rm 'debug.log' 244 | git commit -m "Start ignoring debug.log" 245 | ``` 246 | 247 | Editar .gitignore 248 | === 249 | ```bash 250 | -- Hacer cambios en .gitignore 251 | git rm -r --cached . 252 | git add . 253 | git commit -m "..." 254 | 255 | ``` 256 | 257 | 258 | REFERENCIAS 259 | --- 260 | Reponer archivos eliminados 261 | - https://www.git-tower.com/learn/git/faq/restoring-deleted-files 262 | 263 | - https://www.atlassian.com/git/tutorials/merging-vs-rebasing/conceptual-overview 264 | 265 | - http://www.codigogratis.com.ar/como-utilizar-git-con-hostgator/ 266 | 267 | Fin de línea 268 | - https://stackoverflow.com/questions/5834014/lf-will-be-replaced-by-crlf-in-git-what-is-that-and-is-it-important 269 | -------------------------------------------------------------------------------- /DevOps/lamp.md: -------------------------------------------------------------------------------- 1 | LAMP 2 | === 3 | ```bash 4 | #UBUNTU 16.04 con php 7 y mysql 5.7.x 5 | # Instalar Apache/httpd 6 | sudo apt-get install apache2 7 | # Ver log de errores de apache 8 | vim /var/log/apache2/error.log 9 | 10 | # Instalar MariaDB o mysql 11 | 12 | # MariaDB 13 | sudo apt-get install wget software-properties-common dirmngr ca-certificates apt-transport-https -y 14 | sudo apt update 15 | sudo apt install mariadb-server mariadb-client 16 | sudo mysql_secure_installation 17 | # Mysql 18 | sudo apt-get install mysql-server mysql-client 19 | sudo mysql_secure_installation 20 | 21 | # Habilitar que el usuario root puede loguearse por consola y web 22 | sudo mysql -u root 23 | ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'mi_clave'; 24 | 25 | # PHP multiversion 26 | sudo apt -y install software-properties-common 27 | sudo add-apt-repository -y ppa:ondrej/php 28 | sudo apt update 29 | sudo apt install php7.4 30 | sudo apt install php8.1 31 | sudo apt-get install php-cli 32 | sudo apt-get install libapache2-mod-php 33 | 34 | # Buscar paquetes php a instalar 35 | sudo apt-cache search php 36 | 37 | # Paquetes útiles php 38 | sudo apt-get install php-mysql 39 | sudo apt-get install php-gd 40 | sudo apt-get install php-curl 41 | sudo apt-get install php-cgi 42 | sudo apt-get install php-pear 43 | sudo apt-get install php-mcrypt 44 | sudo apt-get install php7.0-mbstring 45 | sudo apt-get install php-mbstring 46 | sudo apt-get install php-gettext 47 | sudo apt-get install php-bcmath 48 | sudo apt-get install php-dom 49 | 50 | # Desinstalar php completamente 51 | sudo apt-get purge 'php*' 52 | sudo apt-get autoclean 53 | sudo apt-get autoremove 54 | 55 | # Levantar/Detener/Reiniciar servicios(apache2/httpd/mysql) 56 | sudo service apache2 [start/stop/restart] 57 | 58 | # Permitir que el usuario funcione como apache 59 | sudo chown -R usuario:usuario html 60 | sudo usermod -a -G www-data usuario 61 | sudo adduser usuario www-data 62 | 63 | # Deshabilitar que apache levante con el sistema operativo 64 | sudo systemctl disable apache2 65 | # Levantar apache 66 | sudo service apache2 start 67 | ``` 68 | 69 | Rutas amistosas: mod_rewrite 70 | === 71 | ```bash 72 | # UBUNTU 73 | sudo a2enmod rewrite 74 | # En /etc/apache2/sites-available/000-default.conf 75 | 76 | AllowOverride All 77 | 78 | ``` 79 | Hosts virtuales 80 | === 81 | ```bash 82 | # UBUNTU 83 | # Crear archivo midominio.conf 84 | sudo vim /etc/apache2/sites-available/midominio.conf 85 | 86 | # Dentro del archivo copiar, adaptar y guardar 87 | 88 | ServerName www.midominio.com 89 | ServerAlias midominio.com *midominio.com 90 | DocumentRoot /var/www/html/midominio 91 | 92 | 93 | # Crear el link simbólico estando en /etc/apache2/sites-available 94 | sudo a2ensite midominio.conf 95 | 96 | # Agregar los hosts en el archivo 97 | sudo vim etc/hosts 98 | 99 | # Escribir: 100 | 127.0.0.1 midominio.com www.midominio.com 101 | 102 | # Reiniciar apache 103 | sudo service apache2 restart 104 | 105 | # Opcional: Deshabilitar el sitio 106 | sudo a2dissite midominio.com 107 | sudo service apache2 restart 108 | ``` 109 | 110 | PHPMYADMIN 111 | === 112 | ```bash 113 | # UBUNTU 114 | sudo apt-get install phpmyadmin 115 | # crear enlace simbólico 116 | sudo ln -s /usr/share/phpmyadmin /var/www/html 117 | # cambiar el tiempo maximo de session (1440 segundos por defecto) 118 | # Settings->Features->General->Login cookie validity 119 | #Cambiar en php.ini 120 | session.gc_maxlifetime = MismoValorConfigurado 121 | ``` 122 | 123 | Optimizar php 124 | === 125 | ```bash 126 | # UBUNTU 127 | # En /etc/php/7.0/apache2/php.ini 128 | realpath_cache_size = 1024k 129 | realpath_cache_ttl = 3600 130 | max_execution_time = 3600 131 | max_input_time = 3600 132 | memory_limit = 256M 133 | post_max_size = 56M 134 | upload_max_filesize = 256M 135 | # Para ambiente de desarrollo es bueno tener todos los mensajes menos algunos 136 | error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE 137 | ``` 138 | 139 | Optimizar mysql 140 | === 141 | ```bash 142 | # En /etc/mysql/my.cnf 143 | 144 | [mysqld] 145 | query_cache_size = 64M 146 | query_cache_type = ON 147 | max_allowed_packet = 128M 148 | max_connections = 100 149 | 150 | innodb_buffer_pool_size = 3072M 151 | innodb_log_file_size = 1024M 152 | innodb_flush_method = O_DIRECT 153 | innodb_log_buffer_size = 128M 154 | innodb_flush_log_at_trx_commit = 2 155 | sync_binlog = 0 156 | innodb_thread_concurrency = 4 157 | ``` 158 | 159 | Referencias 160 | ==== 161 | Drupal al sur 162 | - http://drupalalsur.org/videos/optimizar-php-y-mysql-para-drupal-7 163 | 164 | Optimizar mysql 165 | - http://www.speedemy.com/17-key-mysql-config-file-settings-mysql-5-7-proof/ 166 | 167 | Instalar php multiversion 168 | - https://www.digitalocean.com/community/tutorials/how-to-install-php-7-4-and-set-up-a-local-development-environment-on-ubuntu-18-04 169 | 170 | Instalar mariabd 171 | - https://www.digitalocean.com/community/tutorials/how-to-install-mariadb-on-ubuntu-22-04 172 | -------------------------------------------------------------------------------- /DevOps/lando.md: -------------------------------------------------------------------------------- 1 | LANDO 2 | ======== 3 | #### Instalar lando en ubuntu 18.04 4 | ``` 5 | Instalar docker 6 | 7 | Descargar archivo instalador para posteriormente insgalarlo 8 | https://github.com/lando/lando/releases 9 | 10 | ``` 11 | 12 | ENLACES Y FUENTES 13 | ================= 14 | Instalar lando 15 | - https://docs.devwithlando.io/installation/installing.html 16 | 17 | Empezar con LANDO 18 | - https://docs.devwithlando.io/started.html 19 | 20 | Un ejemplo de entorno para D8, d9 21 | - https://www.jidr.one/lando-para-desarrollo-drupal -------------------------------------------------------------------------------- /DevOps/linux.md: -------------------------------------------------------------------------------- 1 | Administración sistema operativo 2 | === 3 | ```bash 4 | # Version sistema Operativo 5 | cat /etc/*-release 6 | # Ver memoria utilizada 7 | free 8 | free -m 9 | # Ver los recursos usados por el sistemma 10 | top 11 | htop 12 | # Ver todos los procesos 13 | ps 14 | pstree 15 | # Ejemplos: 16 | ps -A | grep firefox 17 | pgrep firefox 18 | # Matar un proceso dandol el id 19 | kill 20 | # Monitor de procesos en tiempo real: cpu, memoria, capas de red, prioridad, etc 21 | atop 22 | # muestra el tamaño aprox. en GB 23 | df -h 24 | # muestra el tamaño aprox. en nodos 25 | df -i 26 | # Espacio de disco en todas las unidades 27 | df -TH 28 | ``` 29 | 30 | Gestión usuarios 31 | === 32 | ```bash 33 | # Listar usuarios locales 34 | cut -d: -f1 /etc/passwd 35 | # Listar todos los grupos de usuario formato Grupo:Contraseña:ID_Grupo(GID):Lista de usuarios 36 | cat /etc/group 37 | # Agregar usuario y crear su propio grupo 38 | sudo useradd nombre_usuario 39 | # Asignar el usuario al grupo del root 40 | usermod -aG sudo nombre_usuario 41 | # Asignar el usuario al grupo de apache 42 | usermod -aG www-data nombre_usuario 43 | ``` 44 | 45 | Gestion de archivos 46 | === 47 | ```bash 48 | # Ver los permisos de un archivo/carpeta en modo numérico 49 | find carpeta/archivo -printf '%m %p\n' 50 | # Limpiar todo el contenido de un archivo (para limpiar logs) 51 | truncate -s0 error_log 52 | # Ver el peso de una carpeta/archivo recursivamente 53 | du -sh nombre_carpeta 54 | # Calcula el tamaño real de los directorios 55 | du -h --max-depth=1 56 | # Descomprimir tar.gz 57 | tar -xzvf nombre_archivo.tar.gz 58 | # Comprimir tar.gz 59 | tar -zcvf nombre_archivo.tar.gz nombre_carpeta 60 | # Comprimir 7z 61 | 7z a FacturasAExcepcionar.7z FacturasAExcepcionar.txt 62 | # Descomprimir .gz 63 | gunzip nombre_archivo.gz 64 | # Accesos carpeta 65 | cd carpeta 66 | cd .. 67 | # Mover archivos 68 | mv carpeta nueva_carpeta 69 | mv archivo.extension archivo_nuevo.extension 70 | # Copiar archivos 71 | cp -R carpeta nueva_carpeta 72 | cp archivo archivo_nuevo 73 | # Listar archivos 74 | ls 75 | ls /ruta/carpeta 76 | # archivos ocultos 77 | ls -a 78 | # ver propiedades de los archivos 79 | ls -l 80 | # combinamos propiedades y archivos ocultos 81 | ls -la 82 | 83 | # Cambiar permisos 84 | # chmod 775 -R /ruta/carpeta 85 | # 4->lectura 86 | # 2->escritura 87 | # 1->ejecución 88 | 89 | # Cambiar permisos a sólo directorios. 90 | find -type d -print0 |xargs -0 chmod 755 91 | 92 | # Cambiar dueño 93 | chown usuario:grupo /ruta/carpeta 94 | # Crear enlace simbólicos (soft) 95 | ln -s /ruta/carpeta/ nombre_enlace 96 | # Remover enlace simbólico (soft) 97 | unlink nombre_enlace 98 | # Posibilitar que un archivo se ejecute desde cualquier lugar llamando desde la consola 99 | mv archivo.phar /usr/local/bin/nombre_comando 100 | # Buscar en el contenido de los archivos 101 | grep -lir "texto buscado" 102 | # Buscar en el contenido de los archivos con retorno parcial del contenido 103 | grep -r "texto buscado" 104 | # Buscar en determinados tipos de archivos 105 | grep -lir 'langcode' --include \*.schema.yml 106 | ``` 107 | Redes 108 | === 109 | ```bash 110 | #Lista todas las interfaces de red y su estado 111 | rfkill list all 112 | 113 | #Instalar open ssh para permitir acceso remoto 114 | https://www.cyberciti.biz/faq/ubuntu-linux-install-openssh-server/ 115 | ``` 116 | 117 | Gestion Ubuntu 118 | === 119 | ```bash 120 | # Instalar .deb mediante consola 121 | sudo dpkg -i google-chrome-stable_current_i386.deb 122 | 123 | # Trabajar con la consola en múltiples ventanas 124 | sudo apt-get install screen 125 | screen 126 | # Dividir horizontalmente 127 | ctrl a + shift s 128 | # Dividir verticalmente 129 | ctrl a + shift \ 130 | # Cambiar de ventana 131 | ctrl a + tab 132 | # Establecer misma sesión en la ventana 133 | ctrl a + 0-9 134 | # Establecer nueva sesión en la ventana 135 | ctrl a + c 136 | # Redimencionar la ventana 137 | ctrl a :resize enter 138 | # Remover una region 139 | ctrl+a :remove 140 | 141 | #FISH: Utilitario que incrementa la eficiencia con el trabajo en la consola 142 | # Instalar 143 | sudo apt-get install fish 144 | 145 | # Configurar 146 | fish_config 147 | 148 | # Establecer fish como el shell por defecto del sistema operativo. 149 | chsh -s /usr/bin/fish 150 | 151 | # Sin embargo, en Fish, se encadena comandos con ";" en lugar de "&&" por lo que si necesitas concatenar puedes salirte momentaneamente de fish 152 | $ fish bash 153 | ó 154 | $ bash 155 | # Para volver 156 | fish 157 | 158 | # Warp: una utilidad para la terminal que incluyo autocompletar, bloques, ia, drive. 159 | https://www.warp.dev/ 160 | 161 | # Descargar un archivo de internet 162 | wget http://www.nombreweb.com/archivo.ext 163 | 164 | # Reparar sistema de paquetería cuando estan rotos 165 | sudo apt-get -f install 166 | sudo dpkg --configure -a 167 | sudo apt-get autoremove 168 | sudo apt-get clean 169 | sudo rm /var/lib/apt/lists/* -vf 170 | sudo apt-get update 171 | ``` 172 | 173 | Servidor email para envío sólamente desde php 174 | === 175 | ```bash 176 | # Instalamos sendmail 177 | sudo apt-get install sendmail 178 | # Configuramos sendmail (se pone Si a las preguntas) 179 | sudo sendmailconfig 180 | # Editamos el archivo hosts 181 | sudo vim /etc/hosts 182 | 183 | # Ponemos este contenido en el principio del archivo. Comentando si hay algo similar 184 | # 127.0.0.1 localhost localhost.localdomain your_domain_name_here.com 185 | # Ejemplo real: 186 | # 127.0.0.1 localhost localhost.devtest.com skynet 187 | # Reiniciamos apache 188 | 189 | # AYUDAS: 190 | # Obtener el nombre del host (your_domain_name_here.com) 191 | hostname 192 | ``` 193 | 194 | 195 | Buscar y reemplazar 196 | === 197 | ```bash 198 | # Buscar archivos por patrón de nombre: 199 | find /path -type f -iname '*name*' 200 | # Buscar directorios por patrón de nombre: 201 | find /path -type d -iname '*name*' 202 | 203 | # Buscar recursivamente por debajo de directorio actual dentro de archivos por patrón: 204 | grep -rie 'bank' 205 | 206 | # Buscar archivos por nombre y reemplazar por otra palabra (tener cuidado, probar antes comando anterior): 207 | find /path -type f -exec sed -i 's/bank/Bank/g' {} \; 208 | ``` 209 | 210 | Conectar entre servidores 211 | === 212 | ```bash 213 | # Copiar archivo de un servido a tu equipo 214 | sudo scp -P 2222 nombres_usuario@ip_servidor:/ruta_al_archivo /ruta_destino 215 | ``` 216 | 217 | Aplicaciones útiles para desarrollo 218 | === 219 | - Kazam 220 | Permite grabar screenshots, videos de areas de la pantalla. 221 | 222 | - Kompare 223 | Permite comparar 2 carpetas, de manera muy similar a git. 224 | 225 | 226 | Referencias 227 | === 228 | Screen 229 | - http://www.pixelbeat.org/lkdb/screen.html 230 | 231 | Corregir los permisos de los archivos 232 | - http://boomshadow.net/tech/fixes/fixperms-script/ 233 | - https://forums.cpanel.net/threads/fix-permissions-in-accounts.73414/ 234 | 235 | Acceso remoto a servidor por linea de comandos 236 | - http://www.hypexr.org/linux_scp_help.php 237 | 238 | Enviar emails desde php 239 | - http://lukepeters.me/blog/getting-the-php-mail-function-to-work-on-ubuntu 240 | - https://gist.github.com/adamstac/7462202 241 | -------------------------------------------------------------------------------- /DevOps/mysql.md: -------------------------------------------------------------------------------- 1 | MYSQL 2 | ===== 3 | ## Comandos gestion 4 | ```bash 5 | # Reiniciar mysql (ubuntu) 6 | $ service mysql restart 7 | # Reiniciar mysql (fedora) 8 | $ /etc/init.d/mysqld restart 9 | ``` 10 | 11 | ## Comandos administrativos 12 | ```bash 13 | # Ingresar con usario y clave 14 | $ mysql --user=user_name --password=user_password db_name; 15 | # V 16 | $ mysql -u user_name -puser_password db_name; 17 | 18 | # Mostrar bases de datos y tablas 19 | $ SHOW databases; 20 | $ SHOW tables; 21 | 22 | # Crear bases de datos 23 | $ CREATE database db_name; 24 | 25 | # Usar una bases de datos 26 | $ USE db_name; 27 | //una vez que se esta con una base de datos seleccionada se puede ejecutar sql. 28 | 29 | # Salir 30 | $ quit; 31 | 32 | # Crear usuario 33 | $ CREATE USER 'db_user'@'localhost' IDENTIFIED BY 'user_password'; 34 | $ SELECT * FROM mysql.user; 35 | 36 | # Asignar clave a un usuario (ejemplo al usuario root) 37 | $ mysql -u root 38 | SET PASSWORD FOR 'root'@'localhost' = PASSWORD('clave'); 39 | SET PASSWORD FOR 'root'@'127.0.0.1' = PASSWORD('clave'); 40 | SET PASSWORD FOR 'root'@'%' = PASSWORD('clave'); 41 | 42 | # Cambiar de clave 43 | $ mysql -u user_name -p'user_password' new_password 44 | 45 | # Eliminar usuario 46 | $ DROP USER db_user: 47 | 48 | # Privilegios a una base de datos en específico 49 | $ GRANT ALL PRIVILEGES ON db_name.* to 'db_user'@'localhost'; 50 | $ FLUSH PRIVILEGES; 51 | 52 | # Privilegios a todas las bases de datos 53 | $ GRANT ALL PRIVILEGES ON *.* TO 'db_user'@'localhost' WITH GRANT OPTION; 54 | $ FLUSH PRIVILEGES; 55 | 56 | # Otorgar control total 57 | $ GRANT ALL ON *.* TO 'koalasof'@'localhost' WITH GRANT OPTION; 58 | 59 | # Ver privilegios 60 | $ show grants for bd_user@db_host 61 | 62 | # Sacar backup 63 | $ mysqldump --user=[uname] --password=[pwd] [dbname] > [backupfile.sql] 64 | 65 | # Restaurar backup 66 | $ mysql --user=[uname] --password=[pwd] [db_to_restore] < [backupfile.sql] 67 | 68 | ``` 69 | ## Comandos básicos 70 | ```bash 71 | # Eliminar todos los registros de una tabla 72 | $ TRUNCATE TABLE 73 | ``` 74 | ## Estados y configuraciones de la base de datos 75 | ```bash 76 | #Ver de una tabla en específico 77 | $ SHOW TABLE STATUS LIKE 'k_caeb'; 78 | #Ver de los campos de una tabla 79 | $ SELECT COLUMN_NAME, TABLE_NAME, CHARACTER_SET_NAME, COLUMN_TYPE COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'bdcli_octopus_technologies' AND TABLE_NAME = 'k_caeb'; 80 | #Ver de la base de datos 81 | $ SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'bdman_sistema'; 82 | ``` 83 | ## Comandos avanzados 84 | ```bash 85 | #Eliminar varias bases de datos 86 | $ mysql> SELECT CONCAT('DROP DATABASE ',schema_name,' ;') AS stmt FROM information_schema.schemata WHERE schema_name LIKE 'bdkhipu\_%' ESCAPE '\\' ORDER BY schema_name 87 | ``` 88 | 89 | Referencias 90 | === 91 | http://www.rackspace.com/knowledge_center/article/installing-mysql-server-on-centos 92 | -------------------------------------------------------------------------------- /DevOps/php.md: -------------------------------------------------------------------------------- 1 | PHP 2 | === 3 | ### Cambiar entre versiones de php 4 | ```bash 5 | sudo update-alternatives --config php 6 | sudo a2dismod php7.4 7 | sudo a2enmod php8.2 8 | sudo systemctl restart apache2 9 | 10 | sudo a2dismod php8.2 11 | sudo a2enmod php7.4 12 | sudo systemctl restart apache2 13 | 14 | ``` 15 | 16 | #### Comparadores cortos 17 | ```php 18 | // Asignación de valor en if/else. 19 | $result = $condition ? 'foo' : 'bar'; 20 | 21 | // Asignación con conparación a nulo. 22 | $result = $variable ?? 'valor_si_variable_no_es_nulo'; // 'fallback' 23 | ``` 24 | 25 | #### Gestión de rutas, directorio y archivos 26 | ```php 27 | $_SERVER[REQUEST_URI] 28 | //Ruta actual del proyecto 29 | getcwd() 30 | 31 | //Ruta host (sin http://) 32 | $_SERVER[HTTP_HOST] 33 | 34 | //Ruta url despues del host 35 | $_SERVER[REQUEST_URI] 36 | 37 | //Ruta base con protocolo 38 | $baseUri = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]"; 39 | 40 | //Llamar una página en background 41 | $ch = curl_init(); 42 | curl_setopt($ch, CURLOPT_URL, "http://example.com/Set.cgi?Image=1"); 43 | curl_setopt($ch, CURLOPT_HEADER, false); 44 | curl_exec($ch); 45 | curl_close($ch); 46 | ``` 47 | 48 | #### Documentar una variable como una clase 49 | ```php 50 | /* @var $edit_operation_url \Drupal\Core\Url */ 51 | $edit_operation_url = $operations['edit']['url']; 52 | ``` 53 | 54 | #### Gestión de arreglos 55 | ```php 56 | //Recorrido 57 | $arr = [1, 2, 3, 4]; 58 | foreach ($arr as &$value) { 59 | $value = $value * 2; 60 | } 61 | 62 | //Agregar campos en un array asociativo 63 | $options = []; 64 | foreach ($stores as $store) { 65 | $options = $options + [ 66 | $store->getId() => $store->getName(), 67 | ]; 68 | } 69 | 70 | //Agregar array en un array de arrays asociativos 71 | $options = []; 72 | foreach ($stores as $store) { 73 | $options[] = [ 74 | $store->getId() => $store->getName(), 75 | ]; 76 | } 77 | 78 | //Array de arrays asociativos 79 | $eventsTaron[] = [ 80 | 'id' => $idEvent, 81 | 'city' => $event['city_name'], 82 | 'country' => $event['country_name'], 83 | 'place' => $place, 84 | 'product_type' => $productType, 85 | 'date' => $event['event_date'], 86 | ]; 87 | 88 | ``` 89 | 90 | #### Gestión de números 91 | ```php 92 | //Redondeo 93 | round( $my_number, 2, PHP_ROUND_HALF_UP) 94 | ``` 95 | 96 | Gestión de objetos 97 | ``` 98 | //Clonando un objeto 99 | $dateEvent = $event->getInitTime(); 100 | $deadline = clone $dateEvent; 101 | 102 | //Si un objeto es de cierto tipo 103 | if ($questionAnswer instanceof Question) 104 | ... 105 | ``` 106 | 107 | #### Gestion de cadenas 108 | ```php 109 | //Remplazar ocurrencias de una cadena por otra cadena 110 | $resultado = str_replace("texto a remplazar", "texto remplazador", "texto original"); 111 | 112 | //Obtener un pedazo de una cadena 113 | $resultado = substr( "texto original" , 0, 4); //retorna "texto" 114 | 115 | //convertir un arreglo en un string 116 | $array = array('apellido', 'email', 'telefono'); 117 | $comma_separated = implode(",", $array);//apellido,email,telefono 118 | 119 | //posición de una cadena 120 | if (strpos($a,'are') !== false) { 121 | echo 'true'; 122 | } 123 | 124 | //funcion para obtener una cadena entre otras cadenas 125 | function get_string_between($string, $start, $end){ 126 | $string = " ".$string; 127 | $ini = strpos($string,$start); 128 | if ($ini == 0) return ""; 129 | $ini += strlen($start); 130 | $len = strpos($string,$end,$ini) - $ini; 131 | return substr($string,$ini,$len); 132 | } 133 | 134 | $fullstring = "this is my [tag]dog[/tag]"; 135 | $parsed = get_string_between($fullstring, "[tag]", "[/tag]"); 136 | 137 | //Partir una cadena en arreglo 138 | $pieces = explode(" ", $pizza); 139 | 140 | ``` 141 | 142 | #### Timestamp y fechas 143 | ```php 144 | $now = time() //Ahora... 145 | $iniDay = strtotime("midnight", $now); //inicio del día 146 | $endDay = strtotime("tomorrow", $iniDay) - 1; //final del día 147 | 148 | //Año actual 149 | $year = date("Y"); 150 | 151 | //Convertir string a timestamp 152 | $date_of_request = $request->request->get('date_of_request'); 153 | $created = strptime($date_of_request, '%d/%m/%Y'); 154 | $timestamp = mktime(0, 0, 0, $created['tm_mon']+1, $created['tm_mday'], $created['tm_year']+1900); 155 | 156 | //Convertir timestamp a Date 157 | date('m/d/Y', 1299446702); 158 | 159 | //Convertir Date a timestamp 160 | strtotime($time); 161 | 162 | //Aumentar n(30) días a una fecha 163 | $date = date('Y-m-d H:i:s', strtotime($date. ' + 30 days')); 164 | 165 | //Zona horaria Ej: America/La_paz 166 | date_default_timezone_get() 167 | 168 | //UTC 169 | $dec = floatval(date('Z')); 170 | $seconds = $dec; 171 | $hours = intval($dec/3600); 172 | $seconds -= $hours * 3600; 173 | $minutes = floor($seconds / 60); 174 | $utc = $this->getHours($hours).":".$this->getMins($minutes); 175 | 176 | ``` 177 | 178 | #### Errores 179 | ```php 180 | // escribir en el log de errores de apache 181 | error_log("Pablito clavo un clavito...!", 0); 182 | ``` 183 | 184 | #### Javascript 185 | ```php 186 | //Codificar un arreglo php para ser rescatado desde js 187 | $arrayEncodedToJs = json_encode($array); 188 | 189 | //Recuperar en un arreglo de php un arreglo js codificado 190 | $arrayDecodedFromJs = json_decode($array); 191 | ``` 192 | 193 | #### Google API 194 | ```php 195 | //Librería oficial 196 | https://developers.google.com/api-client-library/php/ 197 | 198 | //Repositorio 199 | https://github.com/google/google-api-php-client 200 | 201 | //Lista de apis 202 | https://www.googleapis.com/discovery/v1/apis?fields=items(title,discoveryLink) 203 | 204 | //Lista de scopes de una api (ejemplo Calendar API) 205 | https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest?fields=auth(oauth2(scopes)) 206 | 207 | //Buen post 208 | http://googleappsdeveloper.blogspot.com.es/2012/01/tips-on-using-apis-discovery-service.html 209 | 210 | //Guia completa del API de google 211 | https://developers.google.com/google-apps/products 212 | 213 | ``` 214 | 215 | ### Multiversiones 216 | https://ostechnix.com/how-to-switch-between-multiple-php-versions-in-ubuntu/ 217 | 218 | POO 219 | === 220 | INTERFACES 221 | - Permiten especifcar los métodos que va contener una clase. 222 | - Todos los métodos declarados en una interface son públicos. 223 | - Es posible declarar constructores. 224 | - Pueden ser extendidas por el operador "extend" 225 | - Son clases template de otras clases y en programación moderna se los usa directamente para instanciar esas otras clases que lo usan de template. 226 | ```php 227 | interface iTemplate { 228 | public function setVariable($name, $var); 229 | } 230 | 231 | class Template implements iTemplate { 232 | private $vars = array(); 233 | public function setVariable($name, $var) { 234 | $this->vars[$name] = $var; 235 | } 236 | } 237 | ``` 238 | ```php 239 | // Una clase puede implementar n interfaces. 240 | // Se usa para estandarizar clases. 241 | interface A { 242 | ... 243 | } 244 | interface B { 245 | ... 246 | } 247 | 248 | class C implements A, B { 249 | ... 250 | } 251 | ``` 252 | ```php 253 | // Un interface puede ser implementada por n clases. 254 | // se usa para estandarizar los nombres de los métodos de un grupo de clases equivalentes. 255 | interface A { 256 | ... 257 | } 258 | class B implements A { 259 | ... 260 | } 261 | class C implements A { 262 | ... 263 | } 264 | ``` 265 | 266 | TRAITS 267 | - Permiten declaran métodos abstractos y no abstractos que pueden ser usados por múltiples clases. 268 | - Resuelven el problema de que una clases no puede heredar de muchas otras clases 269 | ```php 270 | trait message1 { 271 | public function msg1() { 272 | echo "OOP is fun! "; 273 | } 274 | } 275 | 276 | class Welcome { 277 | use message1; 278 | } 279 | 280 | $obj = new Welcome(); 281 | $obj->msg1(); 282 | ?> 283 | ``` 284 | 285 | PHP 7 nuevas sintaxis 286 | === 287 | NULLABLE 288 | ```php 289 | // Puede retornar NULL o String 290 | function a(): ?string { } 291 | 292 | // Puede recibir como parámetro NULL o String, pero no "valor vacio" 293 | function test(?string $name) { } 294 | ``` 295 | STRICT MODE 296 | ```php 297 | // Los tipos de datos se respetan de manera estrícta. 298 | .output mi_tabla.sql 14 | sqlite> .dump mi_tabla 15 | sqlite> .quit 16 | 17 | ``` 18 | 19 | Referencias 20 | === 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /DevOps/ssh.md: -------------------------------------------------------------------------------- 1 | SSH 2 | === 3 | ```bash 4 | # Instalación de openssh servidor en sistema ubuntu: suficiente para loguearse remotamente por ssh. 5 | sudo apt-get install openssh-server 6 | 7 | # Logueo remoto por ssh 8 | ssh -p 2222 usuario@200.58.81.32 9 | 10 | # Generar key para conexion en remoto: va a generar una clave privada y una publica .pub 11 | # ed25519 es una solución criptográfica, implementa el algoritmo de firma digital de curva de Edwards EdDSA. 12 | ssh-keygen -t ed25519 -C "algun comentario" 13 | 14 | # Copiar key ssh a servidor remoto: crea una linea en ./ssh/authorized_keys en el servidor remoto y ahora le host puede conectar sin necesidad del password del sistema operativo, sino solo con la clave del key creado. 15 | ssh-copy-id -p 2222 -i ~/.ssh/id_ed25519.pub usuario@200.58.81.32 16 | 17 | # Iniciar conexion sin escribir contraseña. 18 | eval $(ssh-agent) 19 | ssh-add 20 | 21 | # Iniciar conexion sin escribir contraseña de manera permanete. 22 | vim .bashrc 23 | # Agregar 24 | alias ssha = 'eval $(ssh-agent) && ssh-add' 25 | ``` 26 | 27 | 28 | REFERENCIAS 29 | --- 30 | Video explicativo 31 | - https://www.youtube.com/watch?v=-Q4T9wLsvOQ&list=PLT98CRl2KxKEUHie1m24-wkyHpEsa4Y70&index=2 32 | 33 | Documentacion ubuntu 34 | - https://ubuntu.com/server/docs/openssh-server 35 | -------------------------------------------------------------------------------- /DevOps/xdebug.md: -------------------------------------------------------------------------------- 1 | XDEBUG 2 | ======== 3 | 4 | #### Instalar 5 | ``` 6 | Instalar el paquete para desarrolladores php 7 | sudo apt install php7.2-dev 8 | 9 | Obtener archivo con información del entorno php 10 | $ sudo php -i > ~/php-info.txt 11 | 12 | Subir el archivo generado php-info.txt al generador de paso para instalar en 13 | https://xdebug.org/wizard.php 14 | Ejecutar los paso generados... 15 | 16 | Conecta xdebug con el editor 17 | $ sudo apt install php-xdebug 18 | 19 | Editar xdebug.ini 20 | $ sudo vim /etc/php/7.0/mods-available/xdebug.ini 21 | Copiar la siguiente configuración 22 | zend_extension = /usr/lib/php/20170718/xdebug.so 23 | xdebug.remote_autostart = 1 24 | xdebug.remote_enable = 1 25 | xdebug.remote_handler = dbgp 26 | xdebug.remote_host = 127.0.0.1 27 | xdebug.remote_log = /tmp/xdebug_remote.log 28 | xdebug.remote_mode = req 29 | xdebug.remote_port = 9005 #if you want to change the port you can change 30 | 31 | Reiniciar apache 32 | $ sudo service apache2 restart 33 | 34 | ``` 35 | 36 | ENLACES Y FUENTES 37 | ================= 38 | Guía para instalar 39 | https://blog.thamaraiselvam.com/finally-configured-xdebug-with-sublime-text-3-on-ubuntu-17-04-ea19aff56c67 40 | -------------------------------------------------------------------------------- /Ecosistema/SEO.md: -------------------------------------------------------------------------------- 1 | SEO 2 | ======== 3 | 4 | #### Módulos 5 | 6 | Pixeles de facebook 7 | https://www.drupal.org/project/facebook_pixel 8 | 9 | 10 | ### Plataformas google que debes de manejar 11 | Google analitycs 12 | 13 | Google adsense.- Para monetizar un sitio añadiendo publicidad 14 | 15 | Google adwords.- Palabras clave y sus busquedas. 16 | 17 | Google search console.- sitemaps - contro busquedas. 18 | 19 | ENLACES Y FUENTES 20 | ================= 21 | Panorama generar de seo-muldiidiomas 22 | https://www.srijan.net/blog/multilingual-seo-drupal 23 | 24 | Ecosistema de módulos seo 25 | https://www.srijan.net/blog/essential-drupal-seo-modules-to-boost-traffic-on-your-website -------------------------------------------------------------------------------- /Ecosistema/integraciones.md: -------------------------------------------------------------------------------- 1 | INTEGRACIONES 2 | ======== 3 | 4 | #### Datalayer 5 | Integración con googe tag manager para hacer seguimiento de los visitantes mediante etiquetas 6 | https://www.drupal.org/project/datalayer 7 | 8 | 9 | ENLACES Y FUENTES 10 | ================= 11 | -------------------------------------------------------------------------------- /Ecosistema/modulos.md: -------------------------------------------------------------------------------- 1 | MÓDULOS 2 | ======== 3 | 4 | #### Redes sociales 5 | Compartir en redes sociales 6 | - https://www.drupal.org/project/addtoany 7 | 8 | ### Entidades 9 | 10 | ### Campos 11 | Permisos sobre los campos 12 | - https://www.drupal.org/project/field_permissions 13 | 14 | Colocar tamaño máximo a cualquier campo 15 | - https://www.drupal.org/project/maxlength 16 | 17 | ### Menus 18 | Agregar atributos a los links de los menús. 19 | - https://www.drupal.org/project/menu_link_attributes 20 | 21 | ### Vistas 22 | Colocar una vista como un campo en a otras entidades (Manage fields) 23 | - https://www.drupal.org/project/viewsreference 24 | 25 | Filtro alfabetico, fecha granular, rango de fechas 26 | - https://www.drupal.org/project/custom_view_filters 27 | 28 | En filtros: Agregar radiobuttons, checkboxes, seleccionar todos, nunguno 29 | - https://www.drupal.org/project/better_exposed_filters 30 | 31 | ### Layouts 32 | Permitir editar arrastrando la presentación de paragraphs 33 | - https://www.drupal.org/project/layout_paragraphs 34 | 35 | Lista de módulos que extienden layout builder 36 | - https://www.drupal.org/docs/8/core/modules/layout-builder/additional-modules 37 | 38 | ### Media 39 | Enla a la entidad padre. 40 | - https://www.drupal.org/project/media_parent_entity_link 41 | 42 | ### CKEditor 43 | Crear enlace con texto definido. 44 | - https://www.drupal.org/project/ckeditor_link_with_text 45 | 46 | ### Usuarios 47 | Redireccionar despues de loguearse por roles. 48 | - https://www.drupal.org/project/redirect_after_login 49 | 50 | Autenticación con validación mediante email, celular 51 | - https://www.drupal.org/project/tfa 52 | 53 | ### Geolocalización 54 | Almacenar datos geográficos 55 | - https://www.drupal.org/project/geofield 56 | 57 | Mapas compatibles con geofield 58 | - https://www.drupal.org/project/geofield_map 59 | 60 | Para integrar buscador 61 | - https://www.drupal.org/project/geocoder 62 | 63 | ### Subscripciones 64 | Para newsletters 65 | - https://www.drupal.org/project/simplenews 66 | 67 | ### Backups 68 | Entorno para sacar backups 69 | - https://www.droptica.com/blog/how-backup-drupal-overview-backup-and-migrate-module/?amp%25253Butm_medium=rss&%25253Butm_content=rss%25253Futm_source%25253Drss?utm_source=drupal-newsletter&utm_medium=email&utm_campaign=drupal-newsletter-20210225 70 | 71 | ENLACES Y FUENTES 72 | ================= 73 | Cómo crear subtemas, documentación oficial 74 | https://www.drupal.org 75 | /docs/theming-drupal/creating-sub-themes -------------------------------------------------------------------------------- /Front-end/Twig.md: -------------------------------------------------------------------------------- 1 | TWIG 2 | ======== 3 | #### Debuguear (Depurar/destripar variables, errores) 4 | ``` 5 | // Habilitar debug: En sites/default/services.yml 6 | parameters: 7 | twig.config: 8 | debug: true 9 | 10 | // Imprimir variables: Se debe activar los módulos devel y kint 11 | {{ kint(nombre_variable) }} 12 | 13 | // Se puede usar el plugin de firefox "firebug" activando "Show comments" 14 | 15 | ``` 16 | 17 | #### Texto traducible del ingles 18 | ``` 19 | 20 | {% trans %} Hello baby {% endtrans %} 21 | 22 | ``` 23 | #### Texto con contexto e idioma fuente 24 | ``` 25 | 30 | 31 | 32 | ``` 33 | 34 | ENLACES Y FUENTES 35 | ================= 36 | Documentación de la comunidad 37 | https://www.drupal.org/node/1906392 38 | 39 | Sitio oficial de twig contiene documentación 40 | http://twig.sensiolabs.org/ 41 | -------------------------------------------------------------------------------- /Front-end/bootstrap.md: -------------------------------------------------------------------------------- 1 | Bootstrap 2 | ======== 3 | #### Sistema de grilla 4 | Tamaños disponibles 5 | ``` 6 | Extra small <576px 7 | Small ≥576px 8 | Medium ≥768px 9 | Large ≥992px 10 | Extra large ≥1200px 11 | ``` 12 | Clase para filas 13 | ``` 14 | row 15 | ``` 16 | Clases para columnas 17 | 18 | | Extra small | Small | Medium | Large | Extra large | 19 | | ----------- | -------- | -------- | -------- | ----------- | 20 | | .col- | .col-sm- | .col-md- | .col-lg- | .col-xl- | 21 | 22 | #### Responsivo 23 | Tamaños responsivos de Bootstrap 4 24 | ``` 25 | Display 1 (6rem = 90px) 26 | Display 2 (5.5rem = 82.5px) 27 | Display 3 (4.5rem = 67.5px) 28 | Display 4 (3.5rem = 52.5px) 29 | h1 (2.5rem = 40px) 30 | h2 (2rem = 32px) 31 | h3 (1.75rem = 28px) 32 | h4 (1.5rem = 24px) 33 | h5 (1.25rem = 20px) 34 | h6 (1rem = 16px) 35 | p (1rem = 16px) 36 | ``` 37 | Volver responsivo el h1 38 | ``` 39 | h1 {font-size:1rem;} /*1rem = 16px*/ 40 | ``` 41 | 42 | ENLACES Y FUENTES 43 | ================= 44 | Sistema de grilla 45 | https://getbootstrap.com/docs/4.0/layout/grid/ 46 | 47 | Texto responsivo 48 | https://bootstrapcreative.com/can-adjust-text-size-bootstrap-responsive-design/ 49 | -------------------------------------------------------------------------------- /Front-end/javascript.md: -------------------------------------------------------------------------------- 1 | Javascript 2 | ======== 3 | #### 4 | 5 | 1. Implementar Libreria en mi_modulo/hello.libraries.yml 6 | ```yml 7 | hello_world: 8 | version: 1.x 9 | js: 10 | js/hello.js: {} 11 | dependencies: 12 | - core/jquery 13 | - core/drupal 14 | - core/jquery.once 15 | ``` 16 | 17 | 2. Agregar al render la libreria 18 | ```php 19 | $render[#target] = $this->t('Hello'); 20 | $render[#attached] = [ 21 | 'library' => [ 22 | 'mi_modulo/hello_world' 23 | ] 24 | ] 25 | $render['#attached']['drupalSettings'] = [ 26 | 'node_type' => $node->type->entity->label(), 27 | ]; 28 | ``` 29 | 30 | 3. Implementamos el js en Drupal.attachBehaviours (cuando la página esta completamente cargada) 31 | ```js 32 | (function (Drupal, $) { 33 | "use strict"; 34 | Drupal.behaviors.helloWorld = { 35 | attach: function (context, settings) { 36 | var message = '
Hello ' + settings.node_type + '
' 37 | $(document).find('.hello').append(message); 38 | } 39 | } 40 | }) (Drupal, jQuery) 41 | ``` 42 | context:Contiene sólo las partes nuevas de la página. 43 | 44 | settings: Contiene datos pasados desde php (Drupal) 45 | 46 | ENLACES Y FUENTES 47 | ================= 48 | 49 | Estándares de programación js dentro de drupal 50 | - https://www.drupal.org/node/172169 51 | 52 | 53 | Nuevas formas de usar jquery ui 54 | - https://www.drupal.org/docs/upgrading-drupal/upgrading-from-drupal-8-or-later/upgrading-from-drupal-9-to-drupal-10-0/migrating-dependencies-on-core-jquery-ui-libraries -------------------------------------------------------------------------------- /Front-end/jinja.md: -------------------------------------------------------------------------------- 1 | Jinja 2 | ======== 3 | #### Instalación 4 | 5 | ```bash 6 | python3 -m pip install jinja2 7 | ``` 8 | 9 | ENLACES Y FUENTES 10 | ================= 11 | Hello world 12 | - https://www.geeksforgeeks.org/getting-started-with-jinja-template/ 13 | 14 | Documentación oficial 15 | - https://jinja.palletsprojects.com/en/3.1.x/api/ -------------------------------------------------------------------------------- /Front-end/librerias.md: -------------------------------------------------------------------------------- 1 | Librerias 2 | ======== 3 | #### Sobreescribir los estilos de una clase padre 4 | Agregar esto en el archivo .info.yml del Tema 5 | 6 | Para rempplazar un archivo css: 7 | ``` 8 | libraries-override: 9 | classy/base: 10 | css: 11 | component: 12 | css/components/menu.css: css/my-menu.css 13 | ``` 14 | Para deshabilitar: 15 | ``` 16 | libraries-override: 17 | classy/base: 18 | css: 19 | component: 20 | css/components/menu.css: false 21 | ``` 22 | 23 | ENLACES Y FUENTES 24 | ================= -------------------------------------------------------------------------------- /Front-end/preprocess.md: -------------------------------------------------------------------------------- 1 | Preprocess 2 | ======== 3 | #### Sobreescribir un theme 4 | 5 | Para manejar el focal point: 6 | ```php 7 | /** 8 | * Implements hook_preprocess_hook(). 9 | */ 10 | function nombre_theme_preprocess_paragraph__full_width_push(array &$variables) { 11 | $paragraph = $variables['paragraph']; 12 | if ($paragraph->hasField('field_image_media') && !$paragraph->field_image_media->isEmpty()) { 13 | // Get image url. 14 | $entity_type_manager = \Drupal::entityTypeManager(); 15 | $media = $entity_type_manager->getStorage('media')->load($paragraph->field_image_media->target_id); 16 | $file = $entity_type_manager->getStorage('file')->load($media->field_media_image->target_id); 17 | $image_uri = $file->getFileUri(); 18 | $style = $entity_type_manager->getStorage('image_style')->load('style_full_width_push_default'); 19 | $variables['project_image_url'] = $style->buildUrl($image_uri); 20 | // Get image focal point settings. 21 | $variables['project_image_url_focal_point'] = '0 0'; 22 | $crop_type = \Drupal::config('focal_point.settings')->get('crop_type'); 23 | $focal_point_manager = \Drupal::service('focal_point.manager'); 24 | $crop = $focal_point_manager->getCropEntity($file, $crop_type); 25 | if (!$crop->get('x')->isEmpty() && !$crop->get('y')->isEmpty()) { 26 | $x = $crop->get('x')->value; 27 | $y = $crop->get('y')->value; 28 | $focal_point = $focal_point_manager->absoluteToRelative($x, $y, $media->field_media_image->width, $media->field_media_image->height); 29 | $variables['project_image_url_focal_point'] = $focal_point['x'] . '% ' . $focal_point['y'] . '%'; 30 | } 31 | \Drupal::service('renderer')->addCacheableDependency($variables, $media); 32 | } 33 | } 34 | 35 | /** 36 | * Implements hook_preprocess_views_view_unformatted__clubs__clubs_activities_schedule(). 37 | */ 38 | function koala_ecommerce_preprocess_field__commerce_product__title(&$variables) { 39 | /** @var Drupal\commerce_product\Entity\Product $product */ 40 | if ($product = $variables['element']['#object']) { 41 | $product_id = $product->id(); 42 | // @todo work with more than one variation. 43 | $variations = $product->getVariationIds(); 44 | $variation_id = reset($variations); 45 | $category_id = $product->get('field_categoy')->getValue()[0]['target_id']; 46 | $term = Term::load($category_id); 47 | $subcategory_id = 0; 48 | $id = $term->id(); 49 | $parent_id = $term->parent->target_id; 50 | if ($parent_id > 0) { 51 | $category_id = $parent_id; 52 | $subcategory_id = $id; 53 | } 54 | 55 | $params = [ 56 | 'product_id' => $product_id, 57 | 'product_variation_id' => $variation_id, 58 | 'category' => $category_id, 59 | 'subcategory' => $subcategory_id, 60 | ]; 61 | $url = new Url('koala_ecommerce.product_page', $params); 62 | $variables['items'][0]['content']['#url'] = $url; 63 | } 64 | } 65 | ``` -------------------------------------------------------------------------------- /Front-end/sub-temas.md: -------------------------------------------------------------------------------- 1 | Sub-Temas 2 | ======== 3 | #### Estructura de archivos 4 | ``` 5 | ``` 6 | 7 | ENLACES Y FUENTES 8 | ================= 9 | Cómo crear subtemas, documentación oficial 10 | https://www.drupal.org 11 | /docs/theming-drupal/creating-sub-themes -------------------------------------------------------------------------------- /Modulos/drupal_vuejs/drupal_vuejs.info.yml: -------------------------------------------------------------------------------- 1 | name: Drupal vuejs 2 | type: module 3 | description: Example for integration of drupal and vuejs 4 | package: Custom 5 | core: 8.x 6 | core_version_requirement: ^8 || ^9 7 | -------------------------------------------------------------------------------- /Modulos/drupal_vuejs/drupal_vuejs.libraries.yml: -------------------------------------------------------------------------------- 1 | # Third-party library (Vuejs CDN). 2 | vuejs: 3 | remote: https://vuejs.org 4 | version: 2.0.5 5 | license: 6 | name: MIT 7 | url: https://github.com/vuejs/vue/blob/dev/LICENSE 8 | gpl-compatible: true 9 | js: 10 | https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js: {type: external, minified: true} 11 | 12 | # Custom Vuejs functionality. 13 | appvuejs: 14 | version: 1.x 15 | js: 16 | js/appvuejs.js: {} 17 | -------------------------------------------------------------------------------- /Modulos/drupal_vuejs/drupal_vuejs.module: -------------------------------------------------------------------------------- 1 | [ 18 | 'test_var' => NULL, 19 | 'test_var2' => NULL 20 | ], 21 | 'template' => 'twigTest', 22 | ]; 23 | return $theme; 24 | } 25 | -------------------------------------------------------------------------------- /Modulos/drupal_vuejs/drupal_vuejs.permissions.yml: -------------------------------------------------------------------------------- 1 | administer drupal_vuejs configuration: 2 | title: 'Administer drupal_vuejs configuration' 3 | description: 'Optional description.' 4 | restrict access: true 5 | -------------------------------------------------------------------------------- /Modulos/drupal_vuejs/drupal_vuejs.routing.yml: -------------------------------------------------------------------------------- 1 | drupal_vuejs.twigtest: 2 | path: '/drupal-vuejs/test' 3 | defaults: 4 | _title: 'Test of vue js functionality' 5 | _controller: '\Drupal\drupal_vuejs\Controller\drupalVuejsController::testContent' 6 | requirements: 7 | _permission: 'access content' 8 | -------------------------------------------------------------------------------- /Modulos/drupal_vuejs/js/appvuejs.js: -------------------------------------------------------------------------------- 1 | new Vue({ 2 | el: '#app', 3 | 4 | data: { 5 | hello: 'This text can be change!', 6 | names: [ 7 | {firstname: 'Noah', lastname:'Doe'}, 8 | {firstname: 'James', lastname:'Smith'}, 9 | {firstname: 'Oliver', lastname:'Campbell'} 10 | ] 11 | }, 12 | delimiters: ['[[',']]'] 13 | }) -------------------------------------------------------------------------------- /Modulos/drupal_vuejs/src/Controller/drupalVuejsController.php: -------------------------------------------------------------------------------- 1 | 'twigTest', 19 | '#test_var' => $this->t('Example of a page'), 20 | '#test_var2' => $this->t('implemented with Vuejs'), 21 | '#attached' => [ 22 | 'library' => [ 23 | 'drupal_vuejs/vuejs', 24 | 'drupal_vuejs/appvuejs', 25 | ] 26 | ], 27 | '#cache' => array( 28 | 'max-age' => 0, 29 | ), 30 | ]; 31 | 32 | return $content; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Modulos/drupal_vuejs/templates/twigTest.html.twig: -------------------------------------------------------------------------------- 1 |
2 |

{{ test_var }} {{ test_var2 }}

3 |
4 | 5 |
6 |

[[ hello ]]

7 | 8 | 9 |

{% trans %} List generated with Vuejs {% endtrans %}

10 |
    11 |
  • 12 | [[ name.firstname ]] 13 | [[ name.lastname ]] 14 |
  • 15 |
16 |
17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DRUPAL DEVELOPER 2 | ================= 3 | Este proyecto es una guía suficiente, con los conocimientos para desarrollar potentes aplicacines web sibre Drupal 8 y 9. 4 | 5 | principios de esta guía: 6 | 7 | * Va al grano, es decir no contiene teoría ni blabla. 8 | * Contiene comandos y trozos de código útiles. 9 | * Intentar abarcar todos los conocimientos básicos que un programador en Drupal 8 debe tener. 10 | 11 | #### Back-end [semi-completo] 12 | Trozos de código y refencias para realizar trabajos con el API de drupal. 13 | 14 | #### Contribución [completo] 15 | Guías para montar un entorno de contribución productivo y poder corregir-mejorar el código de Drupal. 16 | 17 | #### Ecosistema [empezando] 18 | Módulos, Temas, Distribuciones y recursos disponibles y listos para montar. 19 | 20 | #### Front-end [empezando] 21 | Trozos de código y referencias para trabajar en la GUI que va desplegar drupal. 22 | 23 | #### Infraestructura [semi-completo] 24 | Se trada de guías para montar un ambiente productivo 25 | 26 | #### Utiles [empezando] 27 | Se trada de guías para trabajar con tecnologías complementarias y scripts o herramientas de apoyo 28 | 29 | ##### Jarvis [empezando] 30 | Se trata de una colección de scripts bash que agilizan tareas usuales. 31 | * Para poder ejecutar los comandos desde cualquier ubicación desde la consola es necesario copiarlos a /usr/local/bin 32 | ojo el script debe tener permisos de ejecución 33 | si el sistema es fedora o aws se debe colocar enlace simbólico a /usr/bin 34 | ln -s /usr/local/bin/ /usr/bin/composer/ 35 | 36 | #### POR HACER 37 | 38 | * Corregir trozos de código antiguos que tienen mejores prácticas por estos días. 39 | * Completar las seciones que se encuentran en [empezando] y [semi-completo]. 40 | 41 | #### LLAMADO 42 | Cualquier persona puede contribuir a estos documentos: 43 | * Reportando fallos. 44 | * Solicitando nuevas secciones o aclaraciones. 45 | * Agregando documentación. (pull-request) 46 | -------------------------------------------------------------------------------- /Utiles/archivos/drush: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vacho/DrupalDeveloper/7df3ba942522512a057c689d20cf2fd2466e18d3/Utiles/archivos/drush -------------------------------------------------------------------------------- /Utiles/console.md: -------------------------------------------------------------------------------- 1 | CONSOLE 2 | ======== 3 | 4 | #### Instalar Composer globalmente (pre-requisito) 5 | ```bash 6 | curl -sS https://getcomposer.org/installer | php 7 | sudo mv composer.phar /usr/local/bin/composer 8 | # Para fedora, aws EC2 9 | ln -s /usr/local/bin/composer /usr/bin/composer 10 | ``` 11 | 12 | Console 13 | === 14 | #### Instalar globalmente 15 | ```bash 16 | curl https://drupalconsole.com/installer -L -o drupal.phar 17 | mv drupal.phar /usr/local/bin/drupal 18 | chmod +x /usr/local/bin/drupal 19 | # Probar 20 | drupal list 21 | ``` 22 | 23 | 24 | #### Iniciar las configuraciones de la consola 25 | ```bash 26 | # Inicializar configuraciones por defecto de drupal 27 | drupal init 28 | 29 | # (opcional)Para usar Fish: Crear enlace simbólico 30 | ln -s ~/.console/drupal.fish ~/.config/fish/completions/drupal.fish 31 | ``` 32 | 33 | #### Instalar Drupal 34 | 35 | ```bash 36 | # Bajar drupal 37 | drupal site:new nombreInstancia 8.1.8 38 | 39 | # Instalar drupal 40 | cd nombreInstancia 41 | drupal site:install 42 | 43 | chown www-data:www-data -R sites/default 44 | chmod 755 -R sites/default 45 | drupal cache:rebuild 46 | ``` 47 | 48 | #### Comandos de desarrollo 49 | 50 | ```bash 51 | # Crear un módulo 52 | drupal generate:module 53 | 54 | # Crear una entidad de contenido 55 | drupal generate:entity:content 56 | 57 | # Actualizar entidades despues de hacer modificaciones 58 | drupal update:entities 59 | 60 | # Exportar configuraciones 61 | drupal config_split:export --no-interaction 62 | 63 | # Debuguear una configuración activa 64 | drupal debug:config mi_modulo.mi_plugin --show-overridden 65 | ``` 66 | 67 | #### Comandos útiles 68 | 69 | ```bash 70 | # Limpiar caches 71 | drupal cache:rebuild 72 | # (Se puede elegir que cache limpiar despues de dar Enter, elegir con las fechas arriba, abajo) 73 | 74 | # Instalar un módulo 75 | drupal module:download nombreDelModulo 76 | drupal module:install nombreDelModulo 77 | 78 | # Poner el sitio en modo dev 79 | drupal site:mode dev 80 | 81 | # Poner el sitio en modo prod 82 | drupal site:mode prod 83 | ``` 84 | #### Solución errores comunes 85 | 86 | ```bash 87 | # Timezone America/Tijuana 88 | 89 | # /etc/php5/cli/php.ini 90 | # Editar la línea por ejemplo 91 | # date.timezone = America/La_Paz 92 | 93 | # No quiere ejecutar porque necesita se añadan dependencias en el proyecto 94 | composer require drupal/console:~1.0 --prefer-dist --optimize-autoloader 95 | 96 | # No quiere actualizar dependencia con composer en servidor producción 97 | # 1. Ejecutar en ambiente local 98 | composer update 99 | # 2. Copiar el archivo "composer.lock" de local al servidor de producción 100 | # 3. Ejecutar en el servidor de producción 101 | composer install 102 | ``` 103 | 104 | ENLACES Y FUENTES 105 | ================= 106 | Composer 107 | - https://getcomposer.org/doc/00-intro.md#globally 108 | 109 | Documentación oficial 110 | - https://hechoendrupal.gitbooks.io/drupal-console/content/es/index.html 111 | 112 | Sitio 113 | - https://drupalconsole.com/ 114 | 115 | Repositorio 116 | - https://github.com/hechoendrupal/DrupalConsole 117 | 118 | Resumen de comandos 119 | - http://drupalconsole.com/cheatsheet/ 120 | -------------------------------------------------------------------------------- /Utiles/doxygen.md: -------------------------------------------------------------------------------- 1 | 2 | DOXYGEN 3 | ======== 4 | 5 | #### Instalar doxygen 6 | ```bash 7 | sudo apt-get install doxygen 8 | sudo apt install doxygen-gui 9 | ``` 10 | 11 | #### Generar documentación 12 | ```bash 13 | # Correr GUI para configurar y generar documentación. 14 | doxywizard 15 | ``` 16 | 17 | 18 | ENLACES Y FUENTES 19 | ================= 20 | Instalar en ubuntu 21 | - https://www.tutorialspoint.com/articles/how-to-install-doxygen-on-ubuntu 22 | -------------------------------------------------------------------------------- /Utiles/jarvis/initHostVirtual: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | MDOMAIN="$1" 3 | MEXT="$2" 4 | 5 | if [ $# -ne 2 ] 6 | then 7 | echo "Jarvis: Use $0 {domain} {extension}" 8 | exit 1 9 | fi 10 | 11 | cd /etc/apache2/sites-available/ 12 | 13 | cat > $MDOMAIN.conf << EOF 14 | # Default 15 | 16 | ServerName www.$MDOMAIN.$MEXT 17 | ServerAlias $MDOMAIN.$MEXT *$MDOMAIN.$MEXT 18 | DocumentRoot /var/www/html/$MDOMAIN 19 | 20 | EOF 21 | 22 | echo "127.0.0.1 $MDOMAIN.$MEXT www.$MDOMAIN.$MEXT" >> /etc/hosts 23 | 24 | mkdir /var/www/html/$MDOMAIN 25 | a2ensite $MDOMAIN.conf 26 | service apache2 restart 27 | -------------------------------------------------------------------------------- /Utiles/jarvis/restartDB: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | MHOST="$1" 3 | MUSER="$2" 4 | MPASS="$3" 5 | MDB="$4" 6 | BACKUP="$5" 7 | # Detect paths 8 | MYSQL=$(which mysql) 9 | AWK=$(which awk) 10 | GREP=$(which grep) 11 | if [ $# -ne 5 ] 12 | then 13 | echo "Jarvis: Use $0 {MySQL-Database-Host} {MySQL-User-Name} {MySQL-User-Password} {MySQL-Database-Name} {Backup-file-name}" 14 | echo "Jarvis: I drops all tables from a MySQL" 15 | exit 1 16 | fi 17 | TABLES=$($MYSQL -h $MHOST -u $MUSER -p$MPASS $MDB -e 'show tables' | $AWK '{ print $1}' | $GREP -v '^Tables' ) 18 | for t in $TABLES 19 | do 20 | #echo "Deleting $t table from $MDB database..." 21 | $MYSQL -h $MHOST -u $MUSER -p$MPASS $MDB -e "drop table $t" 22 | done 23 | echo "Jarvis: I delete all tables from $MDB" 24 | mysql --user=$MUSER --password=$MPASS $MDB < $BACKUP 25 | echo "Jarvis: Database $MDB restored to $BACKUP" 26 | -------------------------------------------------------------------------------- /Utiles/javascript.md: -------------------------------------------------------------------------------- 1 | Javascript 2 | === 3 | Arreglos 4 | ```js 5 | // Recorrido de arreglos 6 | array.forEach(function(item){ 7 | ... 8 | }); 9 | 10 | // Quitar elementos 11 | array.splice(posicion, numeroelementos); 12 | 13 | // Agregar elementos 14 | array.push(item); 15 | array.splice(posicion, 0, item1, item2, ..., itemN); 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /Utiles/php.md: -------------------------------------------------------------------------------- 1 | PHP 2 | === 3 | ### Cambiar entre versiones de php 4 | ```bash 5 | sudo update-alternatives --config php 6 | sudo a2dismod php7.4 7 | sudo a2enmod php8.2 8 | 9 | sudo a2dismod php8.2 10 | sudo a2enmod php7.4 11 | 12 | sudo systemctl restart apache2 13 | 14 | ``` 15 | 16 | #### Comparadores cortos 17 | ```php 18 | // Asignación de valor en if/else. 19 | $result = $condition ? 'foo' : 'bar'; 20 | 21 | // Asignación con conparación a nulo. 22 | $result = $variable ?? 'valor_si_variable_no_es_nulo'; // 'fallback' 23 | ``` 24 | 25 | #### Gestión de rutas, directorio y archivos 26 | ```php 27 | $_SERVER[REQUEST_URI] 28 | //Ruta actual del proyecto 29 | getcwd() 30 | 31 | //Ruta host (sin http://) 32 | $_SERVER[HTTP_HOST] 33 | 34 | //Ruta url despues del host 35 | $_SERVER[REQUEST_URI] 36 | 37 | //Ruta base con protocolo 38 | $baseUri = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]"; 39 | 40 | //Llamar una página en background 41 | $ch = curl_init(); 42 | curl_setopt($ch, CURLOPT_URL, "http://example.com/Set.cgi?Image=1"); 43 | curl_setopt($ch, CURLOPT_HEADER, false); 44 | curl_exec($ch); 45 | curl_close($ch); 46 | ``` 47 | 48 | #### Documentar una variable como una clase 49 | ```php 50 | /* @var $edit_operation_url \Drupal\Core\Url */ 51 | $edit_operation_url = $operations['edit']['url']; 52 | ``` 53 | 54 | #### Gestión de arreglos 55 | ```php 56 | //Recorrido 57 | $arr = [1, 2, 3, 4]; 58 | foreach ($arr as &$value) { 59 | $value = $value * 2; 60 | } 61 | 62 | //Agregar campos en un array asociativo 63 | $options = []; 64 | foreach ($stores as $store) { 65 | $options = $options + [ 66 | $store->getId() => $store->getName(), 67 | ]; 68 | } 69 | 70 | //Agregar array en un array de arrays asociativos 71 | $options = []; 72 | foreach ($stores as $store) { 73 | $options[] = [ 74 | $store->getId() => $store->getName(), 75 | ]; 76 | } 77 | 78 | //Array de arrays asociativos 79 | $eventsTaron[] = [ 80 | 'id' => $idEvent, 81 | 'city' => $event['city_name'], 82 | 'country' => $event['country_name'], 83 | 'place' => $place, 84 | 'product_type' => $productType, 85 | 'date' => $event['event_date'], 86 | ]; 87 | 88 | ``` 89 | 90 | #### Gestión de números 91 | ```php 92 | //Redondeo 93 | round( $my_number, 2, PHP_ROUND_HALF_UP) 94 | ``` 95 | 96 | Gestión de objetos 97 | ``` 98 | //Clonando un objeto 99 | $dateEvent = $event->getInitTime(); 100 | $deadline = clone $dateEvent; 101 | 102 | //Si un objeto es de cierto tipo 103 | if ($questionAnswer instanceof Question) 104 | ... 105 | ``` 106 | 107 | #### Gestion de cadenas 108 | ```php 109 | //Remplazar ocurrencias de una cadena por otra cadena 110 | $resultado = str_replace("texto a remplazar", "texto remplazador", "texto original"); 111 | 112 | //Obtener un pedazo de una cadena 113 | $resultado = substr( "texto original" , 0, 4); //retorna "texto" 114 | 115 | //convertir un arreglo en un string 116 | $array = array('apellido', 'email', 'telefono'); 117 | $comma_separated = implode(",", $array);//apellido,email,telefono 118 | 119 | //posición de una cadena 120 | if (strpos($a,'are') !== false) { 121 | echo 'true'; 122 | } 123 | 124 | //funcion para obtener una cadena entre otras cadenas 125 | function get_string_between($string, $start, $end){ 126 | $string = " ".$string; 127 | $ini = strpos($string,$start); 128 | if ($ini == 0) return ""; 129 | $ini += strlen($start); 130 | $len = strpos($string,$end,$ini) - $ini; 131 | return substr($string,$ini,$len); 132 | } 133 | 134 | $fullstring = "this is my [tag]dog[/tag]"; 135 | $parsed = get_string_between($fullstring, "[tag]", "[/tag]"); 136 | 137 | //Partir una cadena en arreglo 138 | $pieces = explode(" ", $pizza); 139 | 140 | ``` 141 | 142 | #### Timestamp y fechas 143 | ```php 144 | $now = time() //Ahora... 145 | $iniDay = strtotime("midnight", $now); //inicio del día 146 | $endDay = strtotime("tomorrow", $iniDay) - 1; //final del día 147 | 148 | //Año actual 149 | $year = date("Y"); 150 | 151 | //Convertir string a timestamp 152 | $date_of_request = $request->request->get('date_of_request'); 153 | $created = strptime($date_of_request, '%d/%m/%Y'); 154 | $timestamp = mktime(0, 0, 0, $created['tm_mon']+1, $created['tm_mday'], $created['tm_year']+1900); 155 | 156 | //Convertir timestamp a Date 157 | date('m/d/Y', 1299446702); 158 | 159 | //Convertir Date a timestamp 160 | strtotime($time); 161 | 162 | //Aumentar n(30) días a una fecha 163 | $date = date('Y-m-d H:i:s', strtotime($date. ' + 30 days')); 164 | 165 | //Zona horaria Ej: America/La_paz 166 | date_default_timezone_get() 167 | 168 | //UTC 169 | $dec = floatval(date('Z')); 170 | $seconds = $dec; 171 | $hours = intval($dec/3600); 172 | $seconds -= $hours * 3600; 173 | $minutes = floor($seconds / 60); 174 | $utc = $this->getHours($hours).":".$this->getMins($minutes); 175 | 176 | ``` 177 | 178 | #### Errores 179 | ```php 180 | // escribir en el log de errores de apache 181 | error_log("Pablito clavo un clavito...!", 0); 182 | ``` 183 | 184 | #### Javascript 185 | ```php 186 | //Codificar un arreglo php para ser rescatado desde js 187 | $arrayEncodedToJs = json_encode($array); 188 | 189 | //Recuperar en un arreglo de php un arreglo js codificado 190 | $arrayDecodedFromJs = json_decode($array); 191 | ``` 192 | 193 | #### Google API 194 | ```php 195 | //Librería oficial 196 | https://developers.google.com/api-client-library/php/ 197 | 198 | //Repositorio 199 | https://github.com/google/google-api-php-client 200 | 201 | //Lista de apis 202 | https://www.googleapis.com/discovery/v1/apis?fields=items(title,discoveryLink) 203 | 204 | //Lista de scopes de una api (ejemplo Calendar API) 205 | https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest?fields=auth(oauth2(scopes)) 206 | 207 | //Buen post 208 | http://googleappsdeveloper.blogspot.com.es/2012/01/tips-on-using-apis-discovery-service.html 209 | 210 | //Guia completa del API de google 211 | https://developers.google.com/google-apps/products 212 | 213 | ``` 214 | 215 | ### Multiversiones 216 | https://ostechnix.com/how-to-switch-between-multiple-php-versions-in-ubuntu/ 217 | 218 | POO 219 | === 220 | INTERFACES 221 | - Permiten especifcar los métodos que va contener una clase. 222 | - Todos los métodos declarados en una interface son públicos. 223 | - Es posible declarar constructores. 224 | - Pueden ser extendidas por el operador "extend" 225 | - Son clases template de otras clases y en programación moderna se los usa directamente para instanciar esas otras clases que lo usan de template. 226 | ```php 227 | interface iTemplate { 228 | public function setVariable($name, $var); 229 | } 230 | 231 | class Template implements iTemplate { 232 | private $vars = array(); 233 | public function setVariable($name, $var) { 234 | $this->vars[$name] = $var; 235 | } 236 | } 237 | ``` 238 | ```php 239 | // Una clase puede implementar n interfaces. 240 | // Se usa para estandarizar clases. 241 | interface A { 242 | ... 243 | } 244 | interface B { 245 | ... 246 | } 247 | 248 | class C implements A, B { 249 | ... 250 | } 251 | ``` 252 | ```php 253 | // Un interface puede ser implementada por n clases. 254 | // se usa para estandarizar los nombres de los métodos de un grupo de clases equivalentes. 255 | interface A { 256 | ... 257 | } 258 | class B implements A { 259 | ... 260 | } 261 | class C implements A { 262 | ... 263 | } 264 | ``` 265 | 266 | TRAITS 267 | - Permiten declaran métodos abstractos y no abstractos que pueden ser usados por múltiples clases. 268 | - Resuelven el problema de que una clases no puede heredar de muchas otras clases 269 | ```php 270 | trait message1 { 271 | public function msg1() { 272 | echo "OOP is fun! "; 273 | } 274 | } 275 | 276 | class Welcome { 277 | use message1; 278 | } 279 | 280 | $obj = new Welcome(); 281 | $obj->msg1(); 282 | ?> 283 | ``` 284 | 285 | PHP 7 nuevas sintaxis 286 | === 287 | NULLABLE 288 | ```php 289 | // Puede retornar NULL o String 290 | function a(): ?string { } 291 | 292 | // Puede recibir como parámetro NULL o String, pero no "valor vacio" 293 | function test(?string $name) { } 294 | ``` 295 | STRICT MODE 296 | ```php 297 | // Los tipos de datos se respetan de manera estrícta. 298 |